diff options
Diffstat (limited to 'drivers/video/atafb.c')
-rw-r--r-- | drivers/video/atafb.c | 3098 |
1 files changed, 3098 insertions, 0 deletions
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c new file mode 100644 index 000000000000..15ec1295bc29 --- /dev/null +++ b/drivers/video/atafb.c | |||
@@ -0,0 +1,3098 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device | ||
3 | * | ||
4 | * Copyright (C) 1994 Martin Schaller & Roman Hodek | ||
5 | * | ||
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. | ||
9 | * | ||
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 | ||
38 | * | ||
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. | ||
42 | * | ||
43 | */ | ||
44 | |||
45 | #define ATAFB_TT | ||
46 | #define ATAFB_STE | ||
47 | #define ATAFB_EXT | ||
48 | #define ATAFB_FALCON | ||
49 | |||
50 | #include <linux/module.h> | ||
51 | #include <linux/kernel.h> | ||
52 | #include <linux/sched.h> | ||
53 | #include <linux/errno.h> | ||
54 | #include <linux/string.h> | ||
55 | #include <linux/mm.h> | ||
56 | #include <linux/tty.h> | ||
57 | #include <linux/slab.h> | ||
58 | #include <linux/delay.h> | ||
59 | #include <linux/init.h> | ||
60 | #include <linux/interrupt.h> | ||
61 | |||
62 | #include <asm/setup.h> | ||
63 | #include <asm/uaccess.h> | ||
64 | #include <asm/pgtable.h> | ||
65 | #include <asm/irq.h> | ||
66 | #include <asm/io.h> | ||
67 | |||
68 | #include <asm/atarihw.h> | ||
69 | #include <asm/atariints.h> | ||
70 | #include <asm/atari_stram.h> | ||
71 | |||
72 | #include <linux/fb.h> | ||
73 | #include <asm/atarikb.h> | ||
74 | |||
75 | #include <video/fbcon.h> | ||
76 | #include <video/fbcon-cfb8.h> | ||
77 | #include <video/fbcon-cfb16.h> | ||
78 | #include <video/fbcon-iplan2p2.h> | ||
79 | #include <video/fbcon-iplan2p4.h> | ||
80 | #include <video/fbcon-iplan2p8.h> | ||
81 | #include <video/fbcon-mfb.h> | ||
82 | |||
83 | |||
84 | #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ | ||
85 | #define SWITCH_SND6 0x40 | ||
86 | #define SWITCH_SND7 0x80 | ||
87 | #define SWITCH_NONE 0x00 | ||
88 | |||
89 | |||
90 | #define up(x, r) (((x) + (r) - 1) & ~((r)-1)) | ||
91 | |||
92 | |||
93 | static int default_par=0; /* default resolution (0=none) */ | ||
94 | |||
95 | static unsigned long default_mem_req=0; | ||
96 | |||
97 | static int hwscroll=-1; | ||
98 | |||
99 | static int use_hwscroll = 1; | ||
100 | |||
101 | static int sttt_xres=640,st_yres=400,tt_yres=480; | ||
102 | static int sttt_xres_virtual=640,sttt_yres_virtual=400; | ||
103 | static int ovsc_offset=0, ovsc_addlen=0; | ||
104 | |||
105 | static struct atafb_par { | ||
106 | void *screen_base; | ||
107 | int yres_virtual; | ||
108 | #if defined ATAFB_TT || defined ATAFB_STE | ||
109 | union { | ||
110 | struct { | ||
111 | int mode; | ||
112 | int sync; | ||
113 | } tt, st; | ||
114 | #endif | ||
115 | #ifdef ATAFB_FALCON | ||
116 | struct falcon_hw { | ||
117 | /* Here are fields for storing a video mode, as direct | ||
118 | * parameters for the hardware. | ||
119 | */ | ||
120 | short sync; | ||
121 | short line_width; | ||
122 | short line_offset; | ||
123 | short st_shift; | ||
124 | short f_shift; | ||
125 | short vid_control; | ||
126 | short vid_mode; | ||
127 | short xoffset; | ||
128 | short hht, hbb, hbe, hdb, hde, hss; | ||
129 | short vft, vbb, vbe, vdb, vde, vss; | ||
130 | /* auxiliary information */ | ||
131 | short mono; | ||
132 | short ste_mode; | ||
133 | short bpp; | ||
134 | } falcon; | ||
135 | #endif | ||
136 | /* Nothing needed for external mode */ | ||
137 | } hw; | ||
138 | } current_par; | ||
139 | |||
140 | /* Don't calculate an own resolution, and thus don't change the one found when | ||
141 | * booting (currently used for the Falcon to keep settings for internal video | ||
142 | * hardware extensions (e.g. ScreenBlaster) */ | ||
143 | static int DontCalcRes = 0; | ||
144 | |||
145 | #ifdef ATAFB_FALCON | ||
146 | #define HHT hw.falcon.hht | ||
147 | #define HBB hw.falcon.hbb | ||
148 | #define HBE hw.falcon.hbe | ||
149 | #define HDB hw.falcon.hdb | ||
150 | #define HDE hw.falcon.hde | ||
151 | #define HSS hw.falcon.hss | ||
152 | #define VFT hw.falcon.vft | ||
153 | #define VBB hw.falcon.vbb | ||
154 | #define VBE hw.falcon.vbe | ||
155 | #define VDB hw.falcon.vdb | ||
156 | #define VDE hw.falcon.vde | ||
157 | #define VSS hw.falcon.vss | ||
158 | #define VCO_CLOCK25 0x04 | ||
159 | #define VCO_CSYPOS 0x10 | ||
160 | #define VCO_VSYPOS 0x20 | ||
161 | #define VCO_HSYPOS 0x40 | ||
162 | #define VCO_SHORTOFFS 0x100 | ||
163 | #define VMO_DOUBLE 0x01 | ||
164 | #define VMO_INTER 0x02 | ||
165 | #define VMO_PREMASK 0x0c | ||
166 | #endif | ||
167 | |||
168 | static struct fb_info fb_info; | ||
169 | |||
170 | static void *screen_base; /* base address of screen */ | ||
171 | static void *real_screen_base; /* (only for Overscan) */ | ||
172 | |||
173 | static int screen_len; | ||
174 | |||
175 | static int current_par_valid=0; | ||
176 | |||
177 | static int mono_moni=0; | ||
178 | |||
179 | static struct display disp; | ||
180 | |||
181 | |||
182 | #ifdef ATAFB_EXT | ||
183 | /* external video handling */ | ||
184 | |||
185 | static unsigned external_xres; | ||
186 | static unsigned external_xres_virtual; | ||
187 | static unsigned external_yres; | ||
188 | /* not needed - atafb will never support panning/hardwarescroll with external | ||
189 | * static unsigned external_yres_virtual; | ||
190 | */ | ||
191 | |||
192 | static unsigned external_depth; | ||
193 | static int external_pmode; | ||
194 | static void *external_addr = 0; | ||
195 | static unsigned long external_len; | ||
196 | static unsigned long external_vgaiobase = 0; | ||
197 | static unsigned int external_bitspercol = 6; | ||
198 | |||
199 | /* | ||
200 | JOE <joe@amber.dinoco.de>: | ||
201 | added card type for external driver, is only needed for | ||
202 | colormap handling. | ||
203 | */ | ||
204 | |||
205 | enum cardtype { IS_VGA, IS_MV300 }; | ||
206 | static enum cardtype external_card_type = IS_VGA; | ||
207 | |||
208 | /* | ||
209 | The MV300 mixes the color registers. So we need an array of munged | ||
210 | indices in order to access the correct reg. | ||
211 | */ | ||
212 | static int MV300_reg_1bit[2]={0,1}; | ||
213 | static int MV300_reg_4bit[16]={ | ||
214 | 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; | ||
215 | static int MV300_reg_8bit[256]={ | ||
216 | 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, | ||
217 | 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, | ||
218 | 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, | ||
219 | 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, | ||
220 | 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, | ||
221 | 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, | ||
222 | 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, | ||
223 | 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, | ||
224 | 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, | ||
225 | 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, | ||
226 | 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, | ||
227 | 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, | ||
228 | 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, | ||
229 | 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, | ||
230 | 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, | ||
231 | 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; | ||
232 | |||
233 | static int *MV300_reg = MV300_reg_8bit; | ||
234 | |||
235 | /* | ||
236 | And on the MV300 it's difficult to read out the hardware palette. So we | ||
237 | just keep track of the set colors in our own array here, and use that! | ||
238 | */ | ||
239 | |||
240 | static struct { unsigned char red,green,blue,pad; } ext_color[256]; | ||
241 | #endif /* ATAFB_EXT */ | ||
242 | |||
243 | |||
244 | static int inverse=0; | ||
245 | |||
246 | extern int fontheight_8x8; | ||
247 | extern int fontwidth_8x8; | ||
248 | extern unsigned char fontdata_8x8[]; | ||
249 | |||
250 | extern int fontheight_8x16; | ||
251 | extern int fontwidth_8x16; | ||
252 | extern unsigned char fontdata_8x16[]; | ||
253 | |||
254 | /* ++roman: This structure abstracts from the underlying hardware (ST(e), | ||
255 | * TT, or Falcon. | ||
256 | * | ||
257 | * int (*detect)( void ) | ||
258 | * This function should detect the current video mode settings and | ||
259 | * store them in atafb_predefined[0] for later reference by the | ||
260 | * user. Return the index+1 of an equivalent predefined mode or 0 | ||
261 | * if there is no such. | ||
262 | * | ||
263 | * int (*encode_fix)( struct fb_fix_screeninfo *fix, | ||
264 | * struct atafb_par *par ) | ||
265 | * This function should fill in the 'fix' structure based on the | ||
266 | * values in the 'par' structure. | ||
267 | * | ||
268 | * int (*decode_var)( struct fb_var_screeninfo *var, | ||
269 | * struct atafb_par *par ) | ||
270 | * Get the video params out of 'var'. If a value doesn't fit, round | ||
271 | * it up, if it's too big, return EINVAL. | ||
272 | * Round up in the following order: bits_per_pixel, xres, yres, | ||
273 | * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, | ||
274 | * horizontal timing, vertical timing. | ||
275 | * | ||
276 | * int (*encode_var)( struct fb_var_screeninfo *var, | ||
277 | * struct atafb_par *par ); | ||
278 | * Fill the 'var' structure based on the values in 'par' and maybe | ||
279 | * other values read out of the hardware. | ||
280 | * | ||
281 | * void (*get_par)( struct atafb_par *par ) | ||
282 | * Fill the hardware's 'par' structure. | ||
283 | * | ||
284 | * void (*set_par)( struct atafb_par *par ) | ||
285 | * Set the hardware according to 'par'. | ||
286 | * | ||
287 | * int (*getcolreg)( unsigned regno, unsigned *red, | ||
288 | * unsigned *green, unsigned *blue, | ||
289 | * unsigned *transp, struct fb_info *info ) | ||
290 | * Read a single color register and split it into | ||
291 | * colors/transparent. Return != 0 for invalid regno. | ||
292 | * | ||
293 | * void (*set_screen_base)(void *s_base) | ||
294 | * Set the base address of the displayed frame buffer. Only called | ||
295 | * if yres_virtual > yres or xres_virtual > xres. | ||
296 | * | ||
297 | * int (*blank)( int blank_mode ) | ||
298 | * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then | ||
299 | * the caller blanks by setting the CLUT to all black. Return 0 if blanking | ||
300 | * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which | ||
301 | * doesn't support it. Implements VESA suspend and powerdown modes on | ||
302 | * hardware that supports disabling hsync/vsync: | ||
303 | * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown. | ||
304 | */ | ||
305 | |||
306 | static struct fb_hwswitch { | ||
307 | int (*detect)( void ); | ||
308 | int (*encode_fix)( struct fb_fix_screeninfo *fix, | ||
309 | struct atafb_par *par ); | ||
310 | int (*decode_var)( struct fb_var_screeninfo *var, | ||
311 | struct atafb_par *par ); | ||
312 | int (*encode_var)( struct fb_var_screeninfo *var, | ||
313 | struct atafb_par *par ); | ||
314 | void (*get_par)( struct atafb_par *par ); | ||
315 | void (*set_par)( struct atafb_par *par ); | ||
316 | int (*getcolreg)( unsigned regno, unsigned *red, | ||
317 | unsigned *green, unsigned *blue, | ||
318 | unsigned *transp, struct fb_info *info ); | ||
319 | void (*set_screen_base)(void *s_base); | ||
320 | int (*blank)( int blank_mode ); | ||
321 | int (*pan_display)( struct fb_var_screeninfo *var, | ||
322 | struct atafb_par *par); | ||
323 | } *fbhw; | ||
324 | |||
325 | static char *autodetect_names[] = {"autodetect", NULL}; | ||
326 | static char *stlow_names[] = {"stlow", NULL}; | ||
327 | static char *stmid_names[] = {"stmid", "default5", NULL}; | ||
328 | static char *sthigh_names[] = {"sthigh", "default4", NULL}; | ||
329 | static char *ttlow_names[] = {"ttlow", NULL}; | ||
330 | static char *ttmid_names[]= {"ttmid", "default1", NULL}; | ||
331 | static char *tthigh_names[]= {"tthigh", "default2", NULL}; | ||
332 | static char *vga2_names[] = {"vga2", NULL}; | ||
333 | static char *vga4_names[] = {"vga4", NULL}; | ||
334 | static char *vga16_names[] = {"vga16", "default3", NULL}; | ||
335 | static char *vga256_names[] = {"vga256", NULL}; | ||
336 | static char *falh2_names[] = {"falh2", NULL}; | ||
337 | static char *falh16_names[] = {"falh16", NULL}; | ||
338 | |||
339 | static char **fb_var_names[] = { | ||
340 | /* Writing the name arrays directly in this array (via "(char *[]){...}") | ||
341 | * crashes gcc 2.5.8 (sigsegv) if the inner array | ||
342 | * contains more than two items. I've also seen that all elements | ||
343 | * were identical to the last (my cross-gcc) :-(*/ | ||
344 | autodetect_names, | ||
345 | stlow_names, | ||
346 | stmid_names, | ||
347 | sthigh_names, | ||
348 | ttlow_names, | ||
349 | ttmid_names, | ||
350 | tthigh_names, | ||
351 | vga2_names, | ||
352 | vga4_names, | ||
353 | vga16_names, | ||
354 | vga256_names, | ||
355 | falh2_names, | ||
356 | falh16_names, | ||
357 | NULL | ||
358 | /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ | ||
359 | }; | ||
360 | |||
361 | static struct fb_var_screeninfo atafb_predefined[] = { | ||
362 | /* | ||
363 | * yres_virtual==0 means use hw-scrolling if possible, else yres | ||
364 | */ | ||
365 | { /* autodetect */ | ||
366 | 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ | ||
367 | {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ | ||
368 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
369 | { /* st low */ | ||
370 | 320, 200, 320, 0, 0, 0, 4, 0, | ||
371 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
372 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
373 | { /* st mid */ | ||
374 | 640, 200, 640, 0, 0, 0, 2, 0, | ||
375 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
376 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
377 | { /* st high */ | ||
378 | 640, 400, 640, 0, 0, 0, 1, 0, | ||
379 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
380 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
381 | { /* tt low */ | ||
382 | 320, 480, 320, 0, 0, 0, 8, 0, | ||
383 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
384 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
385 | { /* tt mid */ | ||
386 | 640, 480, 640, 0, 0, 0, 4, 0, | ||
387 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
388 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
389 | { /* tt high */ | ||
390 | 1280, 960, 1280, 0, 0, 0, 1, 0, | ||
391 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
392 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
393 | { /* vga2 */ | ||
394 | 640, 480, 640, 0, 0, 0, 1, 0, | ||
395 | {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, | ||
396 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
397 | { /* vga4 */ | ||
398 | 640, 480, 640, 0, 0, 0, 2, 0, | ||
399 | {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, | ||
400 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
401 | { /* vga16 */ | ||
402 | 640, 480, 640, 0, 0, 0, 4, 0, | ||
403 | {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, | ||
404 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
405 | { /* vga256 */ | ||
406 | 640, 480, 640, 0, 0, 0, 8, 0, | ||
407 | {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, | ||
408 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
409 | { /* falh2 */ | ||
410 | 896, 608, 896, 0, 0, 0, 1, 0, | ||
411 | {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, | ||
412 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
413 | { /* falh16 */ | ||
414 | 896, 608, 896, 0, 0, 0, 4, 0, | ||
415 | {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, | ||
416 | 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||
417 | }; | ||
418 | |||
419 | static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined); | ||
420 | |||
421 | |||
422 | static int | ||
423 | get_video_mode(char *vname) | ||
424 | { | ||
425 | char ***name_list; | ||
426 | char **name; | ||
427 | int i; | ||
428 | name_list=fb_var_names; | ||
429 | for (i = 0 ; i < num_atafb_predefined ; i++) { | ||
430 | name=*(name_list++); | ||
431 | if (! name || ! *name) | ||
432 | break; | ||
433 | while (*name) { | ||
434 | if (! strcmp(vname, *name)) | ||
435 | return i+1; | ||
436 | name++; | ||
437 | } | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | |||
443 | |||
444 | /* ------------------- TT specific functions ---------------------- */ | ||
445 | |||
446 | #ifdef ATAFB_TT | ||
447 | |||
448 | static int tt_encode_fix( struct fb_fix_screeninfo *fix, | ||
449 | struct atafb_par *par ) | ||
450 | |||
451 | { | ||
452 | int mode; | ||
453 | |||
454 | strcpy(fix->id,"Atari Builtin"); | ||
455 | fix->smem_start = (unsigned long)real_screen_base; | ||
456 | fix->smem_len = screen_len; | ||
457 | fix->type=FB_TYPE_INTERLEAVED_PLANES; | ||
458 | fix->type_aux=2; | ||
459 | fix->visual=FB_VISUAL_PSEUDOCOLOR; | ||
460 | mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK; | ||
461 | if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) { | ||
462 | fix->type=FB_TYPE_PACKED_PIXELS; | ||
463 | fix->type_aux=0; | ||
464 | if (mode == TT_SHIFTER_TTHIGH) | ||
465 | fix->visual=FB_VISUAL_MONO01; | ||
466 | } | ||
467 | fix->xpanstep=0; | ||
468 | fix->ypanstep=1; | ||
469 | fix->ywrapstep=0; | ||
470 | fix->line_length = 0; | ||
471 | fix->accel = FB_ACCEL_ATARIBLITT; | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | |||
476 | static int tt_decode_var( struct fb_var_screeninfo *var, | ||
477 | struct atafb_par *par ) | ||
478 | { | ||
479 | int xres=var->xres; | ||
480 | int yres=var->yres; | ||
481 | int bpp=var->bits_per_pixel; | ||
482 | int linelen; | ||
483 | int yres_virtual = var->yres_virtual; | ||
484 | |||
485 | if (mono_moni) { | ||
486 | if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2) | ||
487 | return -EINVAL; | ||
488 | par->hw.tt.mode=TT_SHIFTER_TTHIGH; | ||
489 | xres=sttt_xres*2; | ||
490 | yres=tt_yres*2; | ||
491 | bpp=1; | ||
492 | } else { | ||
493 | if (bpp > 8 || xres > sttt_xres || yres > tt_yres) | ||
494 | return -EINVAL; | ||
495 | if (bpp > 4) { | ||
496 | if (xres > sttt_xres/2 || yres > tt_yres) | ||
497 | return -EINVAL; | ||
498 | par->hw.tt.mode=TT_SHIFTER_TTLOW; | ||
499 | xres=sttt_xres/2; | ||
500 | yres=tt_yres; | ||
501 | bpp=8; | ||
502 | } | ||
503 | else if (bpp > 2) { | ||
504 | if (xres > sttt_xres || yres > tt_yres) | ||
505 | return -EINVAL; | ||
506 | if (xres > sttt_xres/2 || yres > st_yres/2) { | ||
507 | par->hw.tt.mode=TT_SHIFTER_TTMID; | ||
508 | xres=sttt_xres; | ||
509 | yres=tt_yres; | ||
510 | bpp=4; | ||
511 | } | ||
512 | else { | ||
513 | par->hw.tt.mode=TT_SHIFTER_STLOW; | ||
514 | xres=sttt_xres/2; | ||
515 | yres=st_yres/2; | ||
516 | bpp=4; | ||
517 | } | ||
518 | } | ||
519 | else if (bpp > 1) { | ||
520 | if (xres > sttt_xres || yres > st_yres/2) | ||
521 | return -EINVAL; | ||
522 | par->hw.tt.mode=TT_SHIFTER_STMID; | ||
523 | xres=sttt_xres; | ||
524 | yres=st_yres/2; | ||
525 | bpp=2; | ||
526 | } | ||
527 | else if (var->xres > sttt_xres || var->yres > st_yres) { | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | else { | ||
531 | par->hw.tt.mode=TT_SHIFTER_STHIGH; | ||
532 | xres=sttt_xres; | ||
533 | yres=st_yres; | ||
534 | bpp=1; | ||
535 | } | ||
536 | } | ||
537 | if (yres_virtual <= 0) | ||
538 | yres_virtual = 0; | ||
539 | else if (yres_virtual < yres) | ||
540 | yres_virtual = yres; | ||
541 | if (var->sync & FB_SYNC_EXT) | ||
542 | par->hw.tt.sync=0; | ||
543 | else | ||
544 | par->hw.tt.sync=1; | ||
545 | linelen=xres*bpp/8; | ||
546 | if (yres_virtual * linelen > screen_len && screen_len) | ||
547 | return -EINVAL; | ||
548 | if (yres * linelen > screen_len && screen_len) | ||
549 | return -EINVAL; | ||
550 | if (var->yoffset + yres > yres_virtual && yres_virtual) | ||
551 | return -EINVAL; | ||
552 | par->yres_virtual = yres_virtual; | ||
553 | par->screen_base = screen_base + var->yoffset * linelen; | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int tt_encode_var( struct fb_var_screeninfo *var, | ||
558 | struct atafb_par *par ) | ||
559 | { | ||
560 | int linelen; | ||
561 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
562 | var->red.offset=0; | ||
563 | var->red.length=4; | ||
564 | var->red.msb_right=0; | ||
565 | var->grayscale=0; | ||
566 | |||
567 | var->pixclock=31041; | ||
568 | var->left_margin=120; /* these may be incorrect */ | ||
569 | var->right_margin=100; | ||
570 | var->upper_margin=8; | ||
571 | var->lower_margin=16; | ||
572 | var->hsync_len=140; | ||
573 | var->vsync_len=30; | ||
574 | |||
575 | var->height=-1; | ||
576 | var->width=-1; | ||
577 | |||
578 | if (par->hw.tt.sync & 1) | ||
579 | var->sync=0; | ||
580 | else | ||
581 | var->sync=FB_SYNC_EXT; | ||
582 | |||
583 | switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) { | ||
584 | case TT_SHIFTER_STLOW: | ||
585 | var->xres=sttt_xres/2; | ||
586 | var->xres_virtual=sttt_xres_virtual/2; | ||
587 | var->yres=st_yres/2; | ||
588 | var->bits_per_pixel=4; | ||
589 | break; | ||
590 | case TT_SHIFTER_STMID: | ||
591 | var->xres=sttt_xres; | ||
592 | var->xres_virtual=sttt_xres_virtual; | ||
593 | var->yres=st_yres/2; | ||
594 | var->bits_per_pixel=2; | ||
595 | break; | ||
596 | case TT_SHIFTER_STHIGH: | ||
597 | var->xres=sttt_xres; | ||
598 | var->xres_virtual=sttt_xres_virtual; | ||
599 | var->yres=st_yres; | ||
600 | var->bits_per_pixel=1; | ||
601 | break; | ||
602 | case TT_SHIFTER_TTLOW: | ||
603 | var->xres=sttt_xres/2; | ||
604 | var->xres_virtual=sttt_xres_virtual/2; | ||
605 | var->yres=tt_yres; | ||
606 | var->bits_per_pixel=8; | ||
607 | break; | ||
608 | case TT_SHIFTER_TTMID: | ||
609 | var->xres=sttt_xres; | ||
610 | var->xres_virtual=sttt_xres_virtual; | ||
611 | var->yres=tt_yres; | ||
612 | var->bits_per_pixel=4; | ||
613 | break; | ||
614 | case TT_SHIFTER_TTHIGH: | ||
615 | var->red.length=0; | ||
616 | var->xres=sttt_xres*2; | ||
617 | var->xres_virtual=sttt_xres_virtual*2; | ||
618 | var->yres=tt_yres*2; | ||
619 | var->bits_per_pixel=1; | ||
620 | break; | ||
621 | } | ||
622 | var->blue=var->green=var->red; | ||
623 | var->transp.offset=0; | ||
624 | var->transp.length=0; | ||
625 | var->transp.msb_right=0; | ||
626 | linelen=var->xres_virtual * var->bits_per_pixel / 8; | ||
627 | if (! use_hwscroll) | ||
628 | var->yres_virtual=var->yres; | ||
629 | else if (screen_len) { | ||
630 | if (par->yres_virtual) | ||
631 | var->yres_virtual = par->yres_virtual; | ||
632 | else | ||
633 | /* yres_virtual==0 means use maximum */ | ||
634 | var->yres_virtual = screen_len / linelen; | ||
635 | } else { | ||
636 | if (hwscroll < 0) | ||
637 | var->yres_virtual = 2 * var->yres; | ||
638 | else | ||
639 | var->yres_virtual=var->yres+hwscroll * 16; | ||
640 | } | ||
641 | var->xoffset=0; | ||
642 | if (screen_base) | ||
643 | var->yoffset=(par->screen_base - screen_base)/linelen; | ||
644 | else | ||
645 | var->yoffset=0; | ||
646 | var->nonstd=0; | ||
647 | var->activate=0; | ||
648 | var->vmode=FB_VMODE_NONINTERLACED; | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | |||
653 | static void tt_get_par( struct atafb_par *par ) | ||
654 | { | ||
655 | unsigned long addr; | ||
656 | par->hw.tt.mode=shifter_tt.tt_shiftmode; | ||
657 | par->hw.tt.sync=shifter.syncmode; | ||
658 | addr = ((shifter.bas_hi & 0xff) << 16) | | ||
659 | ((shifter.bas_md & 0xff) << 8) | | ||
660 | ((shifter.bas_lo & 0xff)); | ||
661 | par->screen_base = phys_to_virt(addr); | ||
662 | } | ||
663 | |||
664 | static void tt_set_par( struct atafb_par *par ) | ||
665 | { | ||
666 | shifter_tt.tt_shiftmode=par->hw.tt.mode; | ||
667 | shifter.syncmode=par->hw.tt.sync; | ||
668 | /* only set screen_base if really necessary */ | ||
669 | if (current_par.screen_base != par->screen_base) | ||
670 | fbhw->set_screen_base(par->screen_base); | ||
671 | } | ||
672 | |||
673 | |||
674 | static int tt_getcolreg(unsigned regno, unsigned *red, | ||
675 | unsigned *green, unsigned *blue, | ||
676 | unsigned *transp, struct fb_info *info) | ||
677 | { | ||
678 | int t, col; | ||
679 | |||
680 | if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) | ||
681 | regno += 254; | ||
682 | if (regno > 255) | ||
683 | return 1; | ||
684 | t = tt_palette[regno]; | ||
685 | col = t & 15; | ||
686 | col |= col << 4; | ||
687 | col |= col << 8; | ||
688 | *blue = col; | ||
689 | col = (t >> 4) & 15; | ||
690 | col |= col << 4; | ||
691 | col |= col << 8; | ||
692 | *green = col; | ||
693 | col = (t >> 8) & 15; | ||
694 | col |= col << 4; | ||
695 | col |= col << 8; | ||
696 | *red = col; | ||
697 | *transp = 0; | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | |||
702 | static int tt_setcolreg(unsigned regno, unsigned red, | ||
703 | unsigned green, unsigned blue, | ||
704 | unsigned transp, struct fb_info *info) | ||
705 | { | ||
706 | if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) | ||
707 | regno += 254; | ||
708 | if (regno > 255) | ||
709 | return 1; | ||
710 | tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) | | ||
711 | (blue >> 12)); | ||
712 | if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == | ||
713 | TT_SHIFTER_STHIGH && regno == 254) | ||
714 | tt_palette[0] = 0; | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | |||
719 | static int tt_detect( void ) | ||
720 | |||
721 | { struct atafb_par par; | ||
722 | |||
723 | /* Determine the connected monitor: The DMA sound must be | ||
724 | * disabled before reading the MFP GPIP, because the Sound | ||
725 | * Done Signal and the Monochrome Detect are XORed together! | ||
726 | * | ||
727 | * Even on a TT, we should look if there is a DMA sound. It was | ||
728 | * announced that the Eagle is TT compatible, but only the PCM is | ||
729 | * missing... | ||
730 | */ | ||
731 | if (ATARIHW_PRESENT(PCM_8BIT)) { | ||
732 | tt_dmasnd.ctrl = DMASND_CTRL_OFF; | ||
733 | udelay(20); /* wait a while for things to settle down */ | ||
734 | } | ||
735 | mono_moni = (mfp.par_dt_reg & 0x80) == 0; | ||
736 | |||
737 | tt_get_par(&par); | ||
738 | tt_encode_var(&atafb_predefined[0], &par); | ||
739 | |||
740 | return 1; | ||
741 | } | ||
742 | |||
743 | #endif /* ATAFB_TT */ | ||
744 | |||
745 | /* ------------------- Falcon specific functions ---------------------- */ | ||
746 | |||
747 | #ifdef ATAFB_FALCON | ||
748 | |||
749 | static int mon_type; /* Falcon connected monitor */ | ||
750 | static int f030_bus_width; /* Falcon ram bus width (for vid_control) */ | ||
751 | #define F_MON_SM 0 | ||
752 | #define F_MON_SC 1 | ||
753 | #define F_MON_VGA 2 | ||
754 | #define F_MON_TV 3 | ||
755 | |||
756 | static struct pixel_clock { | ||
757 | unsigned long f; /* f/[Hz] */ | ||
758 | unsigned long t; /* t/[ps] (=1/f) */ | ||
759 | int right, hsync, left; /* standard timing in clock cycles, not pixel */ | ||
760 | /* hsync initialized in falcon_detect() */ | ||
761 | int sync_mask; /* or-mask for hw.falcon.sync to set this clock */ | ||
762 | int control_mask; /* ditto, for hw.falcon.vid_control */ | ||
763 | } | ||
764 | f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25}, | ||
765 | f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, | ||
766 | fext = { 0, 0, 18, 0, 42, 0x1, 0}; | ||
767 | |||
768 | /* VIDEL-prescale values [mon_type][pixel_length from VCO] */ | ||
769 | static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; | ||
770 | |||
771 | /* Default hsync timing [mon_type] in picoseconds */ | ||
772 | static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000}; | ||
773 | |||
774 | #ifdef FBCON_HAS_CFB16 | ||
775 | static u16 fbcon_cfb16_cmap[16]; | ||
776 | #endif | ||
777 | |||
778 | static inline int hxx_prescale(struct falcon_hw *hw) | ||
779 | { | ||
780 | return hw->ste_mode ? 16 : | ||
781 | vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; | ||
782 | } | ||
783 | |||
784 | static int falcon_encode_fix( struct fb_fix_screeninfo *fix, | ||
785 | struct atafb_par *par ) | ||
786 | { | ||
787 | strcpy(fix->id, "Atari Builtin"); | ||
788 | fix->smem_start = (unsigned long)real_screen_base; | ||
789 | fix->smem_len = screen_len; | ||
790 | fix->type = FB_TYPE_INTERLEAVED_PLANES; | ||
791 | fix->type_aux = 2; | ||
792 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
793 | fix->xpanstep = 1; | ||
794 | fix->ypanstep = 1; | ||
795 | fix->ywrapstep = 0; | ||
796 | if (par->hw.falcon.mono) { | ||
797 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
798 | fix->type_aux = 0; | ||
799 | /* no smooth scrolling with longword aligned video mem */ | ||
800 | fix->xpanstep = 32; | ||
801 | } | ||
802 | else if (par->hw.falcon.f_shift & 0x100) { | ||
803 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
804 | fix->type_aux = 0; | ||
805 | /* Is this ok or should it be DIRECTCOLOR? */ | ||
806 | fix->visual = FB_VISUAL_TRUECOLOR; | ||
807 | fix->xpanstep = 2; | ||
808 | } | ||
809 | fix->line_length = 0; | ||
810 | fix->accel = FB_ACCEL_ATARIBLITT; | ||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | |||
815 | static int falcon_decode_var( struct fb_var_screeninfo *var, | ||
816 | struct atafb_par *par ) | ||
817 | { | ||
818 | int bpp = var->bits_per_pixel; | ||
819 | int xres = var->xres; | ||
820 | int yres = var->yres; | ||
821 | int xres_virtual = var->xres_virtual; | ||
822 | int yres_virtual = var->yres_virtual; | ||
823 | int left_margin, right_margin, hsync_len; | ||
824 | int upper_margin, lower_margin, vsync_len; | ||
825 | int linelen; | ||
826 | int interlace = 0, doubleline = 0; | ||
827 | struct pixel_clock *pclock; | ||
828 | int plen; /* width of pixel in clock cycles */ | ||
829 | int xstretch; | ||
830 | int prescale; | ||
831 | int longoffset = 0; | ||
832 | int hfreq, vfreq; | ||
833 | |||
834 | /* | ||
835 | Get the video params out of 'var'. If a value doesn't fit, round | ||
836 | it up, if it's too big, return EINVAL. | ||
837 | Round up in the following order: bits_per_pixel, xres, yres, | ||
838 | xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, | ||
839 | horizontal timing, vertical timing. | ||
840 | |||
841 | There is a maximum of screen resolution determined by pixelclock | ||
842 | and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock. | ||
843 | In interlace mode this is " * " *vfmin <= pixelclock. | ||
844 | Additional constraints: hfreq. | ||
845 | Frequency range for multisync monitors is given via command line. | ||
846 | For TV and SM124 both frequencies are fixed. | ||
847 | |||
848 | X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0) | ||
849 | Y % 16 == 0 to fit 8x16 font | ||
850 | Y % 8 == 0 if Y<400 | ||
851 | |||
852 | Currently interlace and doubleline mode in var are ignored. | ||
853 | On SM124 and TV only the standard resolutions can be used. | ||
854 | */ | ||
855 | |||
856 | /* Reject uninitialized mode */ | ||
857 | if (!xres || !yres || !bpp) | ||
858 | return -EINVAL; | ||
859 | |||
860 | if (mon_type == F_MON_SM && bpp != 1) { | ||
861 | return -EINVAL; | ||
862 | } | ||
863 | else if (bpp <= 1) { | ||
864 | bpp = 1; | ||
865 | par->hw.falcon.f_shift = 0x400; | ||
866 | par->hw.falcon.st_shift = 0x200; | ||
867 | } | ||
868 | else if (bpp <= 2) { | ||
869 | bpp = 2; | ||
870 | par->hw.falcon.f_shift = 0x000; | ||
871 | par->hw.falcon.st_shift = 0x100; | ||
872 | } | ||
873 | else if (bpp <= 4) { | ||
874 | bpp = 4; | ||
875 | par->hw.falcon.f_shift = 0x000; | ||
876 | par->hw.falcon.st_shift = 0x000; | ||
877 | } | ||
878 | else if (bpp <= 8) { | ||
879 | bpp = 8; | ||
880 | par->hw.falcon.f_shift = 0x010; | ||
881 | } | ||
882 | else if (bpp <= 16) { | ||
883 | bpp = 16; /* packed pixel mode */ | ||
884 | par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ | ||
885 | } | ||
886 | else | ||
887 | return -EINVAL; | ||
888 | par->hw.falcon.bpp = bpp; | ||
889 | |||
890 | if (mon_type == F_MON_SM || DontCalcRes) { | ||
891 | /* Skip all calculations. VGA/TV/SC1224 only supported. */ | ||
892 | struct fb_var_screeninfo *myvar = &atafb_predefined[0]; | ||
893 | |||
894 | if (bpp > myvar->bits_per_pixel || | ||
895 | var->xres > myvar->xres || | ||
896 | var->yres > myvar->yres) | ||
897 | return -EINVAL; | ||
898 | fbhw->get_par(par); /* Current par will be new par */ | ||
899 | goto set_screen_base; /* Don't forget this */ | ||
900 | } | ||
901 | |||
902 | /* Only some fixed resolutions < 640x400 */ | ||
903 | if (xres <= 320) | ||
904 | xres = 320; | ||
905 | else if (xres <= 640 && bpp != 16) | ||
906 | xres = 640; | ||
907 | if (yres <= 200) | ||
908 | yres = 200; | ||
909 | else if (yres <= 240) | ||
910 | yres = 240; | ||
911 | else if (yres <= 400) | ||
912 | yres = 400; | ||
913 | |||
914 | /* 2 planes must use STE compatibility mode */ | ||
915 | par->hw.falcon.ste_mode = bpp==2; | ||
916 | par->hw.falcon.mono = bpp==1; | ||
917 | |||
918 | /* Total and visible scanline length must be a multiple of one longword, | ||
919 | * this and the console fontwidth yields the alignment for xres and | ||
920 | * xres_virtual. | ||
921 | * TODO: this way "odd" fontheights are not supported | ||
922 | * | ||
923 | * Special case in STE mode: blank and graphic positions don't align, | ||
924 | * avoid trash at right margin | ||
925 | */ | ||
926 | if (par->hw.falcon.ste_mode) | ||
927 | xres = (xres + 63) & ~63; | ||
928 | else if (bpp == 1) | ||
929 | xres = (xres + 31) & ~31; | ||
930 | else | ||
931 | xres = (xres + 15) & ~15; | ||
932 | if (yres >= 400) | ||
933 | yres = (yres + 15) & ~15; | ||
934 | else | ||
935 | yres = (yres + 7) & ~7; | ||
936 | |||
937 | if (xres_virtual < xres) | ||
938 | xres_virtual = xres; | ||
939 | else if (bpp == 1) | ||
940 | xres_virtual = (xres_virtual + 31) & ~31; | ||
941 | else | ||
942 | xres_virtual = (xres_virtual + 15) & ~15; | ||
943 | |||
944 | if (yres_virtual <= 0) | ||
945 | yres_virtual = 0; | ||
946 | else if (yres_virtual < yres) | ||
947 | yres_virtual = yres; | ||
948 | |||
949 | /* backward bug-compatibility */ | ||
950 | if (var->pixclock > 1) | ||
951 | var->pixclock -= 1; | ||
952 | |||
953 | par->hw.falcon.line_width = bpp * xres / 16; | ||
954 | par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16; | ||
955 | |||
956 | /* single or double pixel width */ | ||
957 | xstretch = (xres < 640) ? 2 : 1; | ||
958 | |||
959 | #if 0 /* SM124 supports only 640x400, this is rejected above */ | ||
960 | if (mon_type == F_MON_SM) { | ||
961 | if (xres != 640 && yres != 400) | ||
962 | return -EINVAL; | ||
963 | plen = 1; | ||
964 | pclock = &f32; | ||
965 | /* SM124-mode is special */ | ||
966 | par->hw.falcon.ste_mode = 1; | ||
967 | par->hw.falcon.f_shift = 0x000; | ||
968 | par->hw.falcon.st_shift = 0x200; | ||
969 | left_margin = hsync_len = 128 / plen; | ||
970 | right_margin = 0; | ||
971 | /* TODO set all margins */ | ||
972 | } | ||
973 | else | ||
974 | #endif | ||
975 | if (mon_type == F_MON_SC || mon_type == F_MON_TV) { | ||
976 | plen = 2 * xstretch; | ||
977 | if (var->pixclock > f32.t * plen) | ||
978 | return -EINVAL; | ||
979 | pclock = &f32; | ||
980 | if (yres > 240) | ||
981 | interlace = 1; | ||
982 | if (var->pixclock == 0) { | ||
983 | /* set some minimal margins which center the screen */ | ||
984 | left_margin = 32; | ||
985 | right_margin = 18; | ||
986 | hsync_len = pclock->hsync / plen; | ||
987 | upper_margin = 31; | ||
988 | lower_margin = 14; | ||
989 | vsync_len = interlace ? 3 : 4; | ||
990 | } else { | ||
991 | left_margin = var->left_margin; | ||
992 | right_margin = var->right_margin; | ||
993 | hsync_len = var->hsync_len; | ||
994 | upper_margin = var->upper_margin; | ||
995 | lower_margin = var->lower_margin; | ||
996 | vsync_len = var->vsync_len; | ||
997 | if (var->vmode & FB_VMODE_INTERLACED) { | ||
998 | upper_margin = (upper_margin + 1) / 2; | ||
999 | lower_margin = (lower_margin + 1) / 2; | ||
1000 | vsync_len = (vsync_len + 1) / 2; | ||
1001 | } else if (var->vmode & FB_VMODE_DOUBLE) { | ||
1002 | upper_margin *= 2; | ||
1003 | lower_margin *= 2; | ||
1004 | vsync_len *= 2; | ||
1005 | } | ||
1006 | } | ||
1007 | } | ||
1008 | else | ||
1009 | { /* F_MON_VGA */ | ||
1010 | if (bpp == 16) | ||
1011 | xstretch = 2; /* Double pixel width only for hicolor */ | ||
1012 | /* Default values are used for vert./hor. timing if no pixelclock given. */ | ||
1013 | if (var->pixclock == 0) { | ||
1014 | int linesize; | ||
1015 | |||
1016 | /* Choose master pixelclock depending on hor. timing */ | ||
1017 | plen = 1 * xstretch; | ||
1018 | if ((plen * xres + f25.right+f25.hsync+f25.left) * | ||
1019 | fb_info.monspecs.hfmin < f25.f) | ||
1020 | pclock = &f25; | ||
1021 | else if ((plen * xres + f32.right+f32.hsync+f32.left) * | ||
1022 | fb_info.monspecs.hfmin < f32.f) | ||
1023 | pclock = &f32; | ||
1024 | else if ((plen * xres + fext.right+fext.hsync+fext.left) * | ||
1025 | fb_info.monspecs.hfmin < fext.f | ||
1026 | && fext.f) | ||
1027 | pclock = &fext; | ||
1028 | else | ||
1029 | return -EINVAL; | ||
1030 | |||
1031 | left_margin = pclock->left / plen; | ||
1032 | right_margin = pclock->right / plen; | ||
1033 | hsync_len = pclock->hsync / plen; | ||
1034 | linesize = left_margin + xres + right_margin + hsync_len; | ||
1035 | upper_margin = 31; | ||
1036 | lower_margin = 11; | ||
1037 | vsync_len = 3; | ||
1038 | } | ||
1039 | else { | ||
1040 | /* Choose largest pixelclock <= wanted clock */ | ||
1041 | int i; | ||
1042 | unsigned long pcl = ULONG_MAX; | ||
1043 | pclock = 0; | ||
1044 | for (i=1; i <= 4; i *= 2) { | ||
1045 | if (f25.t*i >= var->pixclock && f25.t*i < pcl) { | ||
1046 | pcl = f25.t * i; | ||
1047 | pclock = &f25; | ||
1048 | } | ||
1049 | if (f32.t*i >= var->pixclock && f32.t*i < pcl) { | ||
1050 | pcl = f32.t * i; | ||
1051 | pclock = &f32; | ||
1052 | } | ||
1053 | if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) { | ||
1054 | pcl = fext.t * i; | ||
1055 | pclock = &fext; | ||
1056 | } | ||
1057 | } | ||
1058 | if (!pclock) | ||
1059 | return -EINVAL; | ||
1060 | plen = pcl / pclock->t; | ||
1061 | |||
1062 | left_margin = var->left_margin; | ||
1063 | right_margin = var->right_margin; | ||
1064 | hsync_len = var->hsync_len; | ||
1065 | upper_margin = var->upper_margin; | ||
1066 | lower_margin = var->lower_margin; | ||
1067 | vsync_len = var->vsync_len; | ||
1068 | /* Internal unit is [single lines per (half-)frame] */ | ||
1069 | if (var->vmode & FB_VMODE_INTERLACED) { | ||
1070 | /* # lines in half frame */ | ||
1071 | /* External unit is [lines per full frame] */ | ||
1072 | upper_margin = (upper_margin + 1) / 2; | ||
1073 | lower_margin = (lower_margin + 1) / 2; | ||
1074 | vsync_len = (vsync_len + 1) / 2; | ||
1075 | } | ||
1076 | else if (var->vmode & FB_VMODE_DOUBLE) { | ||
1077 | /* External unit is [double lines per frame] */ | ||
1078 | upper_margin *= 2; | ||
1079 | lower_margin *= 2; | ||
1080 | vsync_len *= 2; | ||
1081 | } | ||
1082 | } | ||
1083 | if (pclock == &fext) | ||
1084 | longoffset = 1; /* VIDEL doesn't synchronize on short offset */ | ||
1085 | } | ||
1086 | /* Is video bus bandwidth (32MB/s) too low for this resolution? */ | ||
1087 | /* this is definitely wrong if bus clock != 32MHz */ | ||
1088 | if (pclock->f / plen / 8 * bpp > 32000000L) | ||
1089 | return -EINVAL; | ||
1090 | |||
1091 | if (vsync_len < 1) | ||
1092 | vsync_len = 1; | ||
1093 | |||
1094 | /* include sync lengths in right/lower margin for all calculations */ | ||
1095 | right_margin += hsync_len; | ||
1096 | lower_margin += vsync_len; | ||
1097 | |||
1098 | /* ! In all calculations of margins we use # of lines in half frame | ||
1099 | * (which is a full frame in non-interlace mode), so we can switch | ||
1100 | * between interlace and non-interlace without messing around | ||
1101 | * with these. | ||
1102 | */ | ||
1103 | again: | ||
1104 | /* Set base_offset 128 and video bus width */ | ||
1105 | par->hw.falcon.vid_control = mon_type | f030_bus_width; | ||
1106 | if (!longoffset) | ||
1107 | par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */ | ||
1108 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
1109 | par->hw.falcon.vid_control |= VCO_HSYPOS; | ||
1110 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
1111 | par->hw.falcon.vid_control |= VCO_VSYPOS; | ||
1112 | /* Pixelclock */ | ||
1113 | par->hw.falcon.vid_control |= pclock->control_mask; | ||
1114 | /* External or internal clock */ | ||
1115 | par->hw.falcon.sync = pclock->sync_mask | 0x2; | ||
1116 | /* Pixellength and prescale */ | ||
1117 | par->hw.falcon.vid_mode = (2/plen) << 2; | ||
1118 | if (doubleline) | ||
1119 | par->hw.falcon.vid_mode |= VMO_DOUBLE; | ||
1120 | if (interlace) | ||
1121 | par->hw.falcon.vid_mode |= VMO_INTER; | ||
1122 | |||
1123 | /********************* | ||
1124 | Horizontal timing: unit = [master clock cycles] | ||
1125 | unit of hxx-registers: [master clock cycles * prescale] | ||
1126 | Hxx-registers are 9 bit wide | ||
1127 | |||
1128 | 1 line = ((hht + 2) * 2 * prescale) clock cycles | ||
1129 | |||
1130 | graphic output = hdb & 0x200 ? | ||
1131 | ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: | ||
1132 | ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff | ||
1133 | (this must be a multiple of plen*128/bpp, on VGA pixels | ||
1134 | to the right may be cut off with a bigger right margin) | ||
1135 | |||
1136 | start of graphics relative to start of 1st halfline = hdb & 0x200 ? | ||
1137 | (hdb - hht - 2) * prescale + hdboff : | ||
1138 | hdb * prescale + hdboff | ||
1139 | |||
1140 | end of graphics relative to start of 1st halfline = | ||
1141 | (hde + hht + 2) * prescale + hdeoff | ||
1142 | *********************/ | ||
1143 | /* Calculate VIDEL registers */ | ||
1144 | { | ||
1145 | int hdb_off, hde_off, base_off; | ||
1146 | int gstart, gend1, gend2, align; | ||
1147 | |||
1148 | prescale = hxx_prescale(&par->hw.falcon); | ||
1149 | base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; | ||
1150 | |||
1151 | /* Offsets depend on video mode */ | ||
1152 | /* Offsets are in clock cycles, divide by prescale to | ||
1153 | * calculate hd[be]-registers | ||
1154 | */ | ||
1155 | if (par->hw.falcon.f_shift & 0x100) { | ||
1156 | align = 1; | ||
1157 | hde_off = 0; | ||
1158 | hdb_off = (base_off + 16 * plen) + prescale; | ||
1159 | } | ||
1160 | else { | ||
1161 | align = 128 / bpp; | ||
1162 | hde_off = ((128 / bpp + 2) * plen); | ||
1163 | if (par->hw.falcon.ste_mode) | ||
1164 | hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale; | ||
1165 | else | ||
1166 | hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; | ||
1167 | } | ||
1168 | |||
1169 | gstart = (prescale/2 + plen * left_margin) / prescale; | ||
1170 | /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ | ||
1171 | gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; | ||
1172 | /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ | ||
1173 | gend2 = gstart + xres * plen / prescale; | ||
1174 | par->HHT = plen * (left_margin + xres + right_margin) / | ||
1175 | (2 * prescale) - 2; | ||
1176 | /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ | ||
1177 | |||
1178 | par->HDB = gstart - hdb_off/prescale; | ||
1179 | par->HBE = gstart; | ||
1180 | if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; | ||
1181 | par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; | ||
1182 | par->HBB = gend2 - par->HHT - 2; | ||
1183 | #if 0 | ||
1184 | /* One more Videl constraint: data fetch of two lines must not overlap */ | ||
1185 | if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { | ||
1186 | /* if this happens increase margins, decrease hfreq. */ | ||
1187 | } | ||
1188 | #endif | ||
1189 | if (hde_off % prescale) | ||
1190 | par->HBB++; /* compensate for non matching hde and hbb */ | ||
1191 | par->HSS = par->HHT + 2 - plen * hsync_len / prescale; | ||
1192 | if (par->HSS < par->HBB) | ||
1193 | par->HSS = par->HBB; | ||
1194 | } | ||
1195 | |||
1196 | /* check hor. frequency */ | ||
1197 | hfreq = pclock->f / ((par->HHT+2)*prescale*2); | ||
1198 | if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) { | ||
1199 | /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ | ||
1200 | /* Too high -> enlarge margin */ | ||
1201 | left_margin += 1; | ||
1202 | right_margin += 1; | ||
1203 | goto again; | ||
1204 | } | ||
1205 | if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin) | ||
1206 | return -EINVAL; | ||
1207 | |||
1208 | /* Vxx-registers */ | ||
1209 | /* All Vxx must be odd in non-interlace, since frame starts in the middle | ||
1210 | * of the first displayed line! | ||
1211 | * One frame consists of VFT+1 half lines. VFT+1 must be even in | ||
1212 | * non-interlace, odd in interlace mode for synchronisation. | ||
1213 | * Vxx-registers are 11 bit wide | ||
1214 | */ | ||
1215 | par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ | ||
1216 | par->VDB = par->VBE; | ||
1217 | par->VDE = yres; | ||
1218 | if (!interlace) par->VDE <<= 1; | ||
1219 | if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ | ||
1220 | par->VDE += par->VDB; | ||
1221 | par->VBB = par->VDE; | ||
1222 | par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; | ||
1223 | par->VSS = par->VFT+1 - (vsync_len * 2 - 1); | ||
1224 | /* vbb,vss,vft must be even in interlace mode */ | ||
1225 | if (interlace) { | ||
1226 | par->VBB++; | ||
1227 | par->VSS++; | ||
1228 | par->VFT++; | ||
1229 | } | ||
1230 | |||
1231 | /* V-frequency check, hope I didn't create any loop here. */ | ||
1232 | /* Interlace and doubleline are mutually exclusive. */ | ||
1233 | vfreq = (hfreq * 2) / (par->VFT + 1); | ||
1234 | if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { | ||
1235 | /* Too high -> try again with doubleline */ | ||
1236 | doubleline = 1; | ||
1237 | goto again; | ||
1238 | } | ||
1239 | else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { | ||
1240 | /* Too low -> try again with interlace */ | ||
1241 | interlace = 1; | ||
1242 | goto again; | ||
1243 | } | ||
1244 | else if (vfreq < fb_info.monspecs.vfmin && doubleline) { | ||
1245 | /* Doubleline too low -> clear doubleline and enlarge margins */ | ||
1246 | int lines; | ||
1247 | doubleline = 0; | ||
1248 | for (lines=0; | ||
1249 | (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax; | ||
1250 | lines++) | ||
1251 | ; | ||
1252 | upper_margin += lines; | ||
1253 | lower_margin += lines; | ||
1254 | goto again; | ||
1255 | } | ||
1256 | else if (vfreq > fb_info.monspecs.vfmax && doubleline) { | ||
1257 | /* Doubleline too high -> enlarge margins */ | ||
1258 | int lines; | ||
1259 | for (lines=0; | ||
1260 | (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; | ||
1261 | lines+=2) | ||
1262 | ; | ||
1263 | upper_margin += lines; | ||
1264 | lower_margin += lines; | ||
1265 | goto again; | ||
1266 | } | ||
1267 | else if (vfreq > fb_info.monspecs.vfmax && interlace) { | ||
1268 | /* Interlace, too high -> enlarge margins */ | ||
1269 | int lines; | ||
1270 | for (lines=0; | ||
1271 | (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; | ||
1272 | lines++) | ||
1273 | ; | ||
1274 | upper_margin += lines; | ||
1275 | lower_margin += lines; | ||
1276 | goto again; | ||
1277 | } | ||
1278 | else if (vfreq < fb_info.monspecs.vfmin || | ||
1279 | vfreq > fb_info.monspecs.vfmax) | ||
1280 | return -EINVAL; | ||
1281 | |||
1282 | set_screen_base: | ||
1283 | linelen = xres_virtual * bpp / 8; | ||
1284 | if (yres_virtual * linelen > screen_len && screen_len) | ||
1285 | return -EINVAL; | ||
1286 | if (yres * linelen > screen_len && screen_len) | ||
1287 | return -EINVAL; | ||
1288 | if (var->yoffset + yres > yres_virtual && yres_virtual) | ||
1289 | return -EINVAL; | ||
1290 | par->yres_virtual = yres_virtual; | ||
1291 | par->screen_base = screen_base + var->yoffset * linelen; | ||
1292 | par->hw.falcon.xoffset = 0; | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | static int falcon_encode_var( struct fb_var_screeninfo *var, | ||
1298 | struct atafb_par *par ) | ||
1299 | { | ||
1300 | /* !!! only for VGA !!! */ | ||
1301 | int linelen; | ||
1302 | int prescale, plen; | ||
1303 | int hdb_off, hde_off, base_off; | ||
1304 | struct falcon_hw *hw = &par->hw.falcon; | ||
1305 | |||
1306 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
1307 | /* possible frequencies: 25.175 or 32MHz */ | ||
1308 | var->pixclock = hw->sync & 0x1 ? fext.t : | ||
1309 | hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; | ||
1310 | |||
1311 | var->height=-1; | ||
1312 | var->width=-1; | ||
1313 | |||
1314 | var->sync=0; | ||
1315 | if (hw->vid_control & VCO_HSYPOS) | ||
1316 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
1317 | if (hw->vid_control & VCO_VSYPOS) | ||
1318 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
1319 | |||
1320 | var->vmode = FB_VMODE_NONINTERLACED; | ||
1321 | if (hw->vid_mode & VMO_INTER) | ||
1322 | var->vmode |= FB_VMODE_INTERLACED; | ||
1323 | if (hw->vid_mode & VMO_DOUBLE) | ||
1324 | var->vmode |= FB_VMODE_DOUBLE; | ||
1325 | |||
1326 | /* visible y resolution: | ||
1327 | * Graphics display starts at line VDB and ends at line | ||
1328 | * VDE. If interlace mode off unit of VC-registers is | ||
1329 | * half lines, else lines. | ||
1330 | */ | ||
1331 | var->yres = hw->vde - hw->vdb; | ||
1332 | if (!(var->vmode & FB_VMODE_INTERLACED)) | ||
1333 | var->yres >>= 1; | ||
1334 | if (var->vmode & FB_VMODE_DOUBLE) | ||
1335 | var->yres >>= 1; | ||
1336 | |||
1337 | /* to get bpp, we must examine f_shift and st_shift. | ||
1338 | * f_shift is valid if any of bits no. 10, 8 or 4 | ||
1339 | * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. | ||
1340 | * if bit 10 set then bit 8 and bit 4 don't care... | ||
1341 | * If all these bits are 0 get display depth from st_shift | ||
1342 | * (as for ST and STE) | ||
1343 | */ | ||
1344 | if (hw->f_shift & 0x400) /* 2 colors */ | ||
1345 | var->bits_per_pixel = 1; | ||
1346 | else if (hw->f_shift & 0x100) /* hicolor */ | ||
1347 | var->bits_per_pixel = 16; | ||
1348 | else if (hw->f_shift & 0x010) /* 8 bitplanes */ | ||
1349 | var->bits_per_pixel = 8; | ||
1350 | else if (hw->st_shift == 0) | ||
1351 | var->bits_per_pixel = 4; | ||
1352 | else if (hw->st_shift == 0x100) | ||
1353 | var->bits_per_pixel = 2; | ||
1354 | else /* if (hw->st_shift == 0x200) */ | ||
1355 | var->bits_per_pixel = 1; | ||
1356 | |||
1357 | var->xres = hw->line_width * 16 / var->bits_per_pixel; | ||
1358 | var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel; | ||
1359 | if (hw->xoffset) | ||
1360 | var->xres_virtual += 16; | ||
1361 | |||
1362 | if (var->bits_per_pixel == 16) { | ||
1363 | var->red.offset=11; | ||
1364 | var->red.length=5; | ||
1365 | var->red.msb_right=0; | ||
1366 | var->green.offset=5; | ||
1367 | var->green.length=6; | ||
1368 | var->green.msb_right=0; | ||
1369 | var->blue.offset=0; | ||
1370 | var->blue.length=5; | ||
1371 | var->blue.msb_right=0; | ||
1372 | } | ||
1373 | else { | ||
1374 | var->red.offset=0; | ||
1375 | var->red.length = hw->ste_mode ? 4 : 6; | ||
1376 | var->red.msb_right=0; | ||
1377 | var->grayscale=0; | ||
1378 | var->blue=var->green=var->red; | ||
1379 | } | ||
1380 | var->transp.offset=0; | ||
1381 | var->transp.length=0; | ||
1382 | var->transp.msb_right=0; | ||
1383 | |||
1384 | linelen = var->xres_virtual * var->bits_per_pixel / 8; | ||
1385 | if (screen_len) { | ||
1386 | if (par->yres_virtual) | ||
1387 | var->yres_virtual = par->yres_virtual; | ||
1388 | else | ||
1389 | /* yres_virtual==0 means use maximum */ | ||
1390 | var->yres_virtual = screen_len / linelen; | ||
1391 | } | ||
1392 | else { | ||
1393 | if (hwscroll < 0) | ||
1394 | var->yres_virtual = 2 * var->yres; | ||
1395 | else | ||
1396 | var->yres_virtual=var->yres+hwscroll * 16; | ||
1397 | } | ||
1398 | var->xoffset=0; /* TODO change this */ | ||
1399 | |||
1400 | /* hdX-offsets */ | ||
1401 | prescale = hxx_prescale(hw); | ||
1402 | plen = 4 >> (hw->vid_mode >> 2 & 0x3); | ||
1403 | base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128; | ||
1404 | if (hw->f_shift & 0x100) { | ||
1405 | hde_off = 0; | ||
1406 | hdb_off = (base_off + 16 * plen) + prescale; | ||
1407 | } | ||
1408 | else { | ||
1409 | hde_off = ((128 / var->bits_per_pixel + 2) * plen); | ||
1410 | if (hw->ste_mode) | ||
1411 | hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen) | ||
1412 | + prescale; | ||
1413 | else | ||
1414 | hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen) | ||
1415 | + prescale; | ||
1416 | } | ||
1417 | |||
1418 | /* Right margin includes hsync */ | ||
1419 | var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) - | ||
1420 | (hw->hdb & 0x200 ? 2+hw->hht : 0)); | ||
1421 | if (hw->ste_mode || mon_type!=F_MON_VGA) | ||
1422 | var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; | ||
1423 | else | ||
1424 | /* can't use this in ste_mode, because hbb is +1 off */ | ||
1425 | var->right_margin = prescale * (hw->hht + 2 - hw->hbb); | ||
1426 | var->hsync_len = prescale * (hw->hht + 2 - hw->hss); | ||
1427 | |||
1428 | /* Lower margin includes vsync */ | ||
1429 | var->upper_margin = hw->vdb / 2 ; /* round down to full lines */ | ||
1430 | var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */ | ||
1431 | var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */ | ||
1432 | if (var->vmode & FB_VMODE_INTERLACED) { | ||
1433 | var->upper_margin *= 2; | ||
1434 | var->lower_margin *= 2; | ||
1435 | var->vsync_len *= 2; | ||
1436 | } | ||
1437 | else if (var->vmode & FB_VMODE_DOUBLE) { | ||
1438 | var->upper_margin = (var->upper_margin + 1) / 2; | ||
1439 | var->lower_margin = (var->lower_margin + 1) / 2; | ||
1440 | var->vsync_len = (var->vsync_len + 1) / 2; | ||
1441 | } | ||
1442 | |||
1443 | var->pixclock *= plen; | ||
1444 | var->left_margin /= plen; | ||
1445 | var->right_margin /= plen; | ||
1446 | var->hsync_len /= plen; | ||
1447 | |||
1448 | var->right_margin -= var->hsync_len; | ||
1449 | var->lower_margin -= var->vsync_len; | ||
1450 | |||
1451 | if (screen_base) | ||
1452 | var->yoffset=(par->screen_base - screen_base)/linelen; | ||
1453 | else | ||
1454 | var->yoffset=0; | ||
1455 | var->nonstd=0; /* what is this for? */ | ||
1456 | var->activate=0; | ||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | |||
1461 | static int f_change_mode = 0; | ||
1462 | static struct falcon_hw f_new_mode; | ||
1463 | static int f_pan_display = 0; | ||
1464 | |||
1465 | static void falcon_get_par( struct atafb_par *par ) | ||
1466 | { | ||
1467 | unsigned long addr; | ||
1468 | struct falcon_hw *hw = &par->hw.falcon; | ||
1469 | |||
1470 | hw->line_width = shifter_f030.scn_width; | ||
1471 | hw->line_offset = shifter_f030.off_next; | ||
1472 | hw->st_shift = videl.st_shift & 0x300; | ||
1473 | hw->f_shift = videl.f_shift; | ||
1474 | hw->vid_control = videl.control; | ||
1475 | hw->vid_mode = videl.mode; | ||
1476 | hw->sync = shifter.syncmode & 0x1; | ||
1477 | hw->xoffset = videl.xoffset & 0xf; | ||
1478 | hw->hht = videl.hht; | ||
1479 | hw->hbb = videl.hbb; | ||
1480 | hw->hbe = videl.hbe; | ||
1481 | hw->hdb = videl.hdb; | ||
1482 | hw->hde = videl.hde; | ||
1483 | hw->hss = videl.hss; | ||
1484 | hw->vft = videl.vft; | ||
1485 | hw->vbb = videl.vbb; | ||
1486 | hw->vbe = videl.vbe; | ||
1487 | hw->vdb = videl.vdb; | ||
1488 | hw->vde = videl.vde; | ||
1489 | hw->vss = videl.vss; | ||
1490 | |||
1491 | addr = (shifter.bas_hi & 0xff) << 16 | | ||
1492 | (shifter.bas_md & 0xff) << 8 | | ||
1493 | (shifter.bas_lo & 0xff); | ||
1494 | par->screen_base = phys_to_virt(addr); | ||
1495 | |||
1496 | /* derived parameters */ | ||
1497 | hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100; | ||
1498 | hw->mono = (hw->f_shift & 0x400) || | ||
1499 | ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200); | ||
1500 | } | ||
1501 | |||
1502 | static void falcon_set_par( struct atafb_par *par ) | ||
1503 | { | ||
1504 | f_change_mode = 0; | ||
1505 | |||
1506 | /* only set screen_base if really necessary */ | ||
1507 | if (current_par.screen_base != par->screen_base) | ||
1508 | fbhw->set_screen_base(par->screen_base); | ||
1509 | |||
1510 | /* Don't touch any other registers if we keep the default resolution */ | ||
1511 | if (DontCalcRes) | ||
1512 | return; | ||
1513 | |||
1514 | /* Tell vbl-handler to change video mode. | ||
1515 | * We change modes only on next VBL, to avoid desynchronisation | ||
1516 | * (a shift to the right and wrap around by a random number of pixels | ||
1517 | * in all monochrome modes). | ||
1518 | * This seems to work on my Falcon. | ||
1519 | */ | ||
1520 | f_new_mode = par->hw.falcon; | ||
1521 | f_change_mode = 1; | ||
1522 | } | ||
1523 | |||
1524 | |||
1525 | static irqreturn_t falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp ) | ||
1526 | { | ||
1527 | struct falcon_hw *hw = &f_new_mode; | ||
1528 | |||
1529 | if (f_change_mode) { | ||
1530 | f_change_mode = 0; | ||
1531 | |||
1532 | if (hw->sync & 0x1) { | ||
1533 | /* Enable external pixelclock. This code only for ScreenWonder */ | ||
1534 | *(volatile unsigned short*)0xffff9202 = 0xffbf; | ||
1535 | } | ||
1536 | else { | ||
1537 | /* Turn off external clocks. Read sets all output bits to 1. */ | ||
1538 | *(volatile unsigned short*)0xffff9202; | ||
1539 | } | ||
1540 | shifter.syncmode = hw->sync; | ||
1541 | |||
1542 | videl.hht = hw->hht; | ||
1543 | videl.hbb = hw->hbb; | ||
1544 | videl.hbe = hw->hbe; | ||
1545 | videl.hdb = hw->hdb; | ||
1546 | videl.hde = hw->hde; | ||
1547 | videl.hss = hw->hss; | ||
1548 | videl.vft = hw->vft; | ||
1549 | videl.vbb = hw->vbb; | ||
1550 | videl.vbe = hw->vbe; | ||
1551 | videl.vdb = hw->vdb; | ||
1552 | videl.vde = hw->vde; | ||
1553 | videl.vss = hw->vss; | ||
1554 | |||
1555 | videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ | ||
1556 | if (hw->ste_mode) { | ||
1557 | videl.st_shift = hw->st_shift; /* write enables STE palette */ | ||
1558 | } | ||
1559 | else { | ||
1560 | /* IMPORTANT: | ||
1561 | * set st_shift 0, so we can tell the screen-depth if f_shift==0. | ||
1562 | * Writing 0 to f_shift enables 4 plane Falcon mode but | ||
1563 | * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible | ||
1564 | * with Falcon palette. | ||
1565 | */ | ||
1566 | videl.st_shift = 0; | ||
1567 | /* now back to Falcon palette mode */ | ||
1568 | videl.f_shift = hw->f_shift; | ||
1569 | } | ||
1570 | /* writing to st_shift changed scn_width and vid_mode */ | ||
1571 | videl.xoffset = hw->xoffset; | ||
1572 | shifter_f030.scn_width = hw->line_width; | ||
1573 | shifter_f030.off_next = hw->line_offset; | ||
1574 | videl.control = hw->vid_control; | ||
1575 | videl.mode = hw->vid_mode; | ||
1576 | } | ||
1577 | if (f_pan_display) { | ||
1578 | f_pan_display = 0; | ||
1579 | videl.xoffset = current_par.hw.falcon.xoffset; | ||
1580 | shifter_f030.off_next = current_par.hw.falcon.line_offset; | ||
1581 | } | ||
1582 | return IRQ_HANDLED; | ||
1583 | } | ||
1584 | |||
1585 | |||
1586 | static int falcon_pan_display( struct fb_var_screeninfo *var, | ||
1587 | struct atafb_par *par ) | ||
1588 | { | ||
1589 | int xoffset; | ||
1590 | int bpp = fb_display[fb_info.currcon].var.bits_per_pixel; | ||
1591 | |||
1592 | if (bpp == 1) | ||
1593 | var->xoffset = up(var->xoffset, 32); | ||
1594 | if (bpp != 16) | ||
1595 | par->hw.falcon.xoffset = var->xoffset & 15; | ||
1596 | else { | ||
1597 | par->hw.falcon.xoffset = 0; | ||
1598 | var->xoffset = up(var->xoffset, 2); | ||
1599 | } | ||
1600 | par->hw.falcon.line_offset = bpp * | ||
1601 | (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; | ||
1602 | if (par->hw.falcon.xoffset) | ||
1603 | par->hw.falcon.line_offset -= bpp; | ||
1604 | xoffset = var->xoffset - par->hw.falcon.xoffset; | ||
1605 | |||
1606 | par->screen_base = screen_base + | ||
1607 | (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8; | ||
1608 | if (fbhw->set_screen_base) | ||
1609 | fbhw->set_screen_base (par->screen_base); | ||
1610 | else | ||
1611 | return -EINVAL; /* shouldn't happen */ | ||
1612 | f_pan_display = 1; | ||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | |||
1617 | static int falcon_getcolreg( unsigned regno, unsigned *red, | ||
1618 | unsigned *green, unsigned *blue, | ||
1619 | unsigned *transp, struct fb_info *info ) | ||
1620 | { unsigned long col; | ||
1621 | |||
1622 | if (regno > 255) | ||
1623 | return 1; | ||
1624 | /* This works in STE-mode (with 4bit/color) since f030_col-registers | ||
1625 | * hold up to 6bit/color. | ||
1626 | * Even with hicolor r/g/b=5/6/5 bit! | ||
1627 | */ | ||
1628 | col = f030_col[regno]; | ||
1629 | *red = (col >> 16) & 0xff00; | ||
1630 | *green = (col >> 8) & 0xff00; | ||
1631 | *blue = (col << 8) & 0xff00; | ||
1632 | *transp = 0; | ||
1633 | return 0; | ||
1634 | } | ||
1635 | |||
1636 | |||
1637 | static int falcon_setcolreg( unsigned regno, unsigned red, | ||
1638 | unsigned green, unsigned blue, | ||
1639 | unsigned transp, struct fb_info *info ) | ||
1640 | { | ||
1641 | if (regno > 255) | ||
1642 | return 1; | ||
1643 | f030_col[regno] = (((red & 0xfc00) << 16) | | ||
1644 | ((green & 0xfc00) << 8) | | ||
1645 | ((blue & 0xfc00) >> 8)); | ||
1646 | if (regno < 16) { | ||
1647 | shifter_tt.color_reg[regno] = | ||
1648 | (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | | ||
1649 | (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | | ||
1650 | ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); | ||
1651 | #ifdef FBCON_HAS_CFB16 | ||
1652 | fbcon_cfb16_cmap[regno] = ((red & 0xf800) | | ||
1653 | ((green & 0xfc00) >> 5) | | ||
1654 | ((blue & 0xf800) >> 11)); | ||
1655 | #endif | ||
1656 | } | ||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1660 | |||
1661 | static int falcon_blank( int blank_mode ) | ||
1662 | { | ||
1663 | /* ++guenther: we can switch off graphics by changing VDB and VDE, | ||
1664 | * so VIDEL doesn't hog the bus while saving. | ||
1665 | * (this may affect usleep()). | ||
1666 | */ | ||
1667 | int vdb, vss, hbe, hss; | ||
1668 | |||
1669 | if (mon_type == F_MON_SM) /* this doesn't work on SM124 */ | ||
1670 | return 1; | ||
1671 | |||
1672 | vdb = current_par.VDB; | ||
1673 | vss = current_par.VSS; | ||
1674 | hbe = current_par.HBE; | ||
1675 | hss = current_par.HSS; | ||
1676 | |||
1677 | if (blank_mode >= 1) { | ||
1678 | /* disable graphics output (this speeds up the CPU) ... */ | ||
1679 | vdb = current_par.VFT + 1; | ||
1680 | /* ... and blank all lines */ | ||
1681 | hbe = current_par.HHT + 2; | ||
1682 | } | ||
1683 | /* use VESA suspend modes on VGA monitors */ | ||
1684 | if (mon_type == F_MON_VGA) { | ||
1685 | if (blank_mode == 2 || blank_mode == 4) | ||
1686 | vss = current_par.VFT + 1; | ||
1687 | if (blank_mode == 3 || blank_mode == 4) | ||
1688 | hss = current_par.HHT + 2; | ||
1689 | } | ||
1690 | |||
1691 | videl.vdb = vdb; | ||
1692 | videl.vss = vss; | ||
1693 | videl.hbe = hbe; | ||
1694 | videl.hss = hss; | ||
1695 | |||
1696 | return 0; | ||
1697 | } | ||
1698 | |||
1699 | |||
1700 | static int falcon_detect( void ) | ||
1701 | { | ||
1702 | struct atafb_par par; | ||
1703 | unsigned char fhw; | ||
1704 | |||
1705 | /* Determine connected monitor and set monitor parameters */ | ||
1706 | fhw = *(unsigned char*)0xffff8006; | ||
1707 | mon_type = fhw >> 6 & 0x3; | ||
1708 | /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */ | ||
1709 | f030_bus_width = fhw << 6 & 0x80; | ||
1710 | switch (mon_type) { | ||
1711 | case F_MON_SM: | ||
1712 | fb_info.monspecs.vfmin = 70; | ||
1713 | fb_info.monspecs.vfmax = 72; | ||
1714 | fb_info.monspecs.hfmin = 35713; | ||
1715 | fb_info.monspecs.hfmax = 35715; | ||
1716 | break; | ||
1717 | case F_MON_SC: | ||
1718 | case F_MON_TV: | ||
1719 | /* PAL...NTSC */ | ||
1720 | fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ | ||
1721 | fb_info.monspecs.vfmax = 60; | ||
1722 | fb_info.monspecs.hfmin = 15620; | ||
1723 | fb_info.monspecs.hfmax = 15755; | ||
1724 | break; | ||
1725 | } | ||
1726 | /* initialize hsync-len */ | ||
1727 | f25.hsync = h_syncs[mon_type] / f25.t; | ||
1728 | f32.hsync = h_syncs[mon_type] / f32.t; | ||
1729 | if (fext.t) | ||
1730 | fext.hsync = h_syncs[mon_type] / fext.t; | ||
1731 | |||
1732 | falcon_get_par(&par); | ||
1733 | falcon_encode_var(&atafb_predefined[0], &par); | ||
1734 | |||
1735 | /* Detected mode is always the "autodetect" slot */ | ||
1736 | return 1; | ||
1737 | } | ||
1738 | |||
1739 | #endif /* ATAFB_FALCON */ | ||
1740 | |||
1741 | /* ------------------- ST(E) specific functions ---------------------- */ | ||
1742 | |||
1743 | #ifdef ATAFB_STE | ||
1744 | |||
1745 | static int stste_encode_fix( struct fb_fix_screeninfo *fix, | ||
1746 | struct atafb_par *par ) | ||
1747 | |||
1748 | { | ||
1749 | int mode; | ||
1750 | |||
1751 | strcpy(fix->id,"Atari Builtin"); | ||
1752 | fix->smem_start = (unsigned long)real_screen_base; | ||
1753 | fix->smem_len = screen_len; | ||
1754 | fix->type = FB_TYPE_INTERLEAVED_PLANES; | ||
1755 | fix->type_aux = 2; | ||
1756 | fix->visual = FB_VISUAL_PSEUDOCOLOR; | ||
1757 | mode = par->hw.st.mode & 3; | ||
1758 | if (mode == ST_HIGH) { | ||
1759 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
1760 | fix->type_aux = 0; | ||
1761 | fix->visual = FB_VISUAL_MONO10; | ||
1762 | } | ||
1763 | if (ATARIHW_PRESENT(EXTD_SHIFTER)) { | ||
1764 | fix->xpanstep = 16; | ||
1765 | fix->ypanstep = 1; | ||
1766 | } else { | ||
1767 | fix->xpanstep = 0; | ||
1768 | fix->ypanstep = 0; | ||
1769 | } | ||
1770 | fix->ywrapstep = 0; | ||
1771 | fix->line_length = 0; | ||
1772 | fix->accel = FB_ACCEL_ATARIBLITT; | ||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | |||
1777 | static int stste_decode_var( struct fb_var_screeninfo *var, | ||
1778 | struct atafb_par *par ) | ||
1779 | { | ||
1780 | int xres=var->xres; | ||
1781 | int yres=var->yres; | ||
1782 | int bpp=var->bits_per_pixel; | ||
1783 | int linelen; | ||
1784 | int yres_virtual = var->yres_virtual; | ||
1785 | |||
1786 | if (mono_moni) { | ||
1787 | if (bpp > 1 || xres > sttt_xres || yres > st_yres) | ||
1788 | return -EINVAL; | ||
1789 | par->hw.st.mode=ST_HIGH; | ||
1790 | xres=sttt_xres; | ||
1791 | yres=st_yres; | ||
1792 | bpp=1; | ||
1793 | } else { | ||
1794 | if (bpp > 4 || xres > sttt_xres || yres > st_yres) | ||
1795 | return -EINVAL; | ||
1796 | if (bpp > 2) { | ||
1797 | if (xres > sttt_xres/2 || yres > st_yres/2) | ||
1798 | return -EINVAL; | ||
1799 | par->hw.st.mode=ST_LOW; | ||
1800 | xres=sttt_xres/2; | ||
1801 | yres=st_yres/2; | ||
1802 | bpp=4; | ||
1803 | } | ||
1804 | else if (bpp > 1) { | ||
1805 | if (xres > sttt_xres || yres > st_yres/2) | ||
1806 | return -EINVAL; | ||
1807 | par->hw.st.mode=ST_MID; | ||
1808 | xres=sttt_xres; | ||
1809 | yres=st_yres/2; | ||
1810 | bpp=2; | ||
1811 | } | ||
1812 | else | ||
1813 | return -EINVAL; | ||
1814 | } | ||
1815 | if (yres_virtual <= 0) | ||
1816 | yres_virtual = 0; | ||
1817 | else if (yres_virtual < yres) | ||
1818 | yres_virtual = yres; | ||
1819 | if (var->sync & FB_SYNC_EXT) | ||
1820 | par->hw.st.sync=(par->hw.st.sync & ~1) | 1; | ||
1821 | else | ||
1822 | par->hw.st.sync=(par->hw.st.sync & ~1); | ||
1823 | linelen=xres*bpp/8; | ||
1824 | if (yres_virtual * linelen > screen_len && screen_len) | ||
1825 | return -EINVAL; | ||
1826 | if (yres * linelen > screen_len && screen_len) | ||
1827 | return -EINVAL; | ||
1828 | if (var->yoffset + yres > yres_virtual && yres_virtual) | ||
1829 | return -EINVAL; | ||
1830 | par->yres_virtual = yres_virtual; | ||
1831 | par->screen_base=screen_base+ var->yoffset*linelen; | ||
1832 | return 0; | ||
1833 | } | ||
1834 | |||
1835 | static int stste_encode_var( struct fb_var_screeninfo *var, | ||
1836 | struct atafb_par *par ) | ||
1837 | { | ||
1838 | int linelen; | ||
1839 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
1840 | var->red.offset=0; | ||
1841 | var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; | ||
1842 | var->red.msb_right=0; | ||
1843 | var->grayscale=0; | ||
1844 | |||
1845 | var->pixclock=31041; | ||
1846 | var->left_margin=120; /* these are incorrect */ | ||
1847 | var->right_margin=100; | ||
1848 | var->upper_margin=8; | ||
1849 | var->lower_margin=16; | ||
1850 | var->hsync_len=140; | ||
1851 | var->vsync_len=30; | ||
1852 | |||
1853 | var->height=-1; | ||
1854 | var->width=-1; | ||
1855 | |||
1856 | if (!(par->hw.st.sync & 1)) | ||
1857 | var->sync=0; | ||
1858 | else | ||
1859 | var->sync=FB_SYNC_EXT; | ||
1860 | |||
1861 | switch (par->hw.st.mode & 3) { | ||
1862 | case ST_LOW: | ||
1863 | var->xres=sttt_xres/2; | ||
1864 | var->yres=st_yres/2; | ||
1865 | var->bits_per_pixel=4; | ||
1866 | break; | ||
1867 | case ST_MID: | ||
1868 | var->xres=sttt_xres; | ||
1869 | var->yres=st_yres/2; | ||
1870 | var->bits_per_pixel=2; | ||
1871 | break; | ||
1872 | case ST_HIGH: | ||
1873 | var->xres=sttt_xres; | ||
1874 | var->yres=st_yres; | ||
1875 | var->bits_per_pixel=1; | ||
1876 | break; | ||
1877 | } | ||
1878 | var->blue=var->green=var->red; | ||
1879 | var->transp.offset=0; | ||
1880 | var->transp.length=0; | ||
1881 | var->transp.msb_right=0; | ||
1882 | var->xres_virtual=sttt_xres_virtual; | ||
1883 | linelen=var->xres_virtual * var->bits_per_pixel / 8; | ||
1884 | ovsc_addlen=linelen*(sttt_yres_virtual - st_yres); | ||
1885 | |||
1886 | if (! use_hwscroll) | ||
1887 | var->yres_virtual=var->yres; | ||
1888 | else if (screen_len) { | ||
1889 | if (par->yres_virtual) | ||
1890 | var->yres_virtual = par->yres_virtual; | ||
1891 | else | ||
1892 | /* yres_virtual==0 means use maximum */ | ||
1893 | var->yres_virtual = screen_len / linelen; | ||
1894 | } | ||
1895 | else { | ||
1896 | if (hwscroll < 0) | ||
1897 | var->yres_virtual = 2 * var->yres; | ||
1898 | else | ||
1899 | var->yres_virtual=var->yres+hwscroll * 16; | ||
1900 | } | ||
1901 | var->xoffset=0; | ||
1902 | if (screen_base) | ||
1903 | var->yoffset=(par->screen_base - screen_base)/linelen; | ||
1904 | else | ||
1905 | var->yoffset=0; | ||
1906 | var->nonstd=0; | ||
1907 | var->activate=0; | ||
1908 | var->vmode=FB_VMODE_NONINTERLACED; | ||
1909 | return 0; | ||
1910 | } | ||
1911 | |||
1912 | |||
1913 | static void stste_get_par( struct atafb_par *par ) | ||
1914 | { | ||
1915 | unsigned long addr; | ||
1916 | par->hw.st.mode=shifter_tt.st_shiftmode; | ||
1917 | par->hw.st.sync=shifter.syncmode; | ||
1918 | addr = ((shifter.bas_hi & 0xff) << 16) | | ||
1919 | ((shifter.bas_md & 0xff) << 8); | ||
1920 | if (ATARIHW_PRESENT(EXTD_SHIFTER)) | ||
1921 | addr |= (shifter.bas_lo & 0xff); | ||
1922 | par->screen_base = phys_to_virt(addr); | ||
1923 | } | ||
1924 | |||
1925 | static void stste_set_par( struct atafb_par *par ) | ||
1926 | { | ||
1927 | shifter_tt.st_shiftmode=par->hw.st.mode; | ||
1928 | shifter.syncmode=par->hw.st.sync; | ||
1929 | /* only set screen_base if really necessary */ | ||
1930 | if (current_par.screen_base != par->screen_base) | ||
1931 | fbhw->set_screen_base(par->screen_base); | ||
1932 | } | ||
1933 | |||
1934 | |||
1935 | static int stste_getcolreg(unsigned regno, unsigned *red, | ||
1936 | unsigned *green, unsigned *blue, | ||
1937 | unsigned *transp, struct fb_info *info) | ||
1938 | { | ||
1939 | unsigned col, t; | ||
1940 | |||
1941 | if (regno > 15) | ||
1942 | return 1; | ||
1943 | col = shifter_tt.color_reg[regno]; | ||
1944 | if (ATARIHW_PRESENT(EXTD_SHIFTER)) { | ||
1945 | t = ((col >> 7) & 0xe) | ((col >> 11) & 1); | ||
1946 | t |= t << 4; | ||
1947 | *red = t | (t << 8); | ||
1948 | t = ((col >> 3) & 0xe) | ((col >> 7) & 1); | ||
1949 | t |= t << 4; | ||
1950 | *green = t | (t << 8); | ||
1951 | t = ((col << 1) & 0xe) | ((col >> 3) & 1); | ||
1952 | t |= t << 4; | ||
1953 | *blue = t | (t << 8); | ||
1954 | } | ||
1955 | else { | ||
1956 | t = (col >> 7) & 0xe; | ||
1957 | t |= t << 4; | ||
1958 | *red = t | (t << 8); | ||
1959 | t = (col >> 3) & 0xe; | ||
1960 | t |= t << 4; | ||
1961 | *green = t | (t << 8); | ||
1962 | t = (col << 1) & 0xe; | ||
1963 | t |= t << 4; | ||
1964 | *blue = t | (t << 8); | ||
1965 | } | ||
1966 | *transp = 0; | ||
1967 | return 0; | ||
1968 | } | ||
1969 | |||
1970 | |||
1971 | static int stste_setcolreg(unsigned regno, unsigned red, | ||
1972 | unsigned green, unsigned blue, | ||
1973 | unsigned transp, struct fb_info *info) | ||
1974 | { | ||
1975 | if (regno > 15) | ||
1976 | return 1; | ||
1977 | red >>= 12; | ||
1978 | blue >>= 12; | ||
1979 | green >>= 12; | ||
1980 | if (ATARIHW_PRESENT(EXTD_SHIFTER)) | ||
1981 | shifter_tt.color_reg[regno] = | ||
1982 | (((red & 0xe) >> 1) | ((red & 1) << 3) << 8) | | ||
1983 | (((green & 0xe) >> 1) | ((green & 1) << 3) << 4) | | ||
1984 | ((blue & 0xe) >> 1) | ((blue & 1) << 3); | ||
1985 | else | ||
1986 | shifter_tt.color_reg[regno] = | ||
1987 | ((red & 0xe) << 7) | | ||
1988 | ((green & 0xe) << 3) | | ||
1989 | ((blue & 0xe) >> 1); | ||
1990 | return 0; | ||
1991 | } | ||
1992 | |||
1993 | |||
1994 | static int stste_detect( void ) | ||
1995 | |||
1996 | { struct atafb_par par; | ||
1997 | |||
1998 | /* Determine the connected monitor: The DMA sound must be | ||
1999 | * disabled before reading the MFP GPIP, because the Sound | ||
2000 | * Done Signal and the Monochrome Detect are XORed together! | ||
2001 | */ | ||
2002 | if (ATARIHW_PRESENT(PCM_8BIT)) { | ||
2003 | tt_dmasnd.ctrl = DMASND_CTRL_OFF; | ||
2004 | udelay(20); /* wait a while for things to settle down */ | ||
2005 | } | ||
2006 | mono_moni = (mfp.par_dt_reg & 0x80) == 0; | ||
2007 | |||
2008 | stste_get_par(&par); | ||
2009 | stste_encode_var(&atafb_predefined[0], &par); | ||
2010 | |||
2011 | if (!ATARIHW_PRESENT(EXTD_SHIFTER)) | ||
2012 | use_hwscroll = 0; | ||
2013 | return 1; | ||
2014 | } | ||
2015 | |||
2016 | static void stste_set_screen_base(void *s_base) | ||
2017 | { | ||
2018 | unsigned long addr; | ||
2019 | addr= virt_to_phys(s_base); | ||
2020 | /* Setup Screen Memory */ | ||
2021 | shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); | ||
2022 | shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); | ||
2023 | if (ATARIHW_PRESENT(EXTD_SHIFTER)) | ||
2024 | shifter.bas_lo=(unsigned char) (addr & 0x0000ff); | ||
2025 | } | ||
2026 | |||
2027 | #endif /* ATAFB_STE */ | ||
2028 | |||
2029 | /* Switching the screen size should be done during vsync, otherwise | ||
2030 | * the margins may get messed up. This is a well known problem of | ||
2031 | * the ST's video system. | ||
2032 | * | ||
2033 | * Unfortunately there is hardly any way to find the vsync, as the | ||
2034 | * vertical blank interrupt is no longer in time on machines with | ||
2035 | * overscan type modifications. | ||
2036 | * | ||
2037 | * We can, however, use Timer B to safely detect the black shoulder, | ||
2038 | * but then we've got to guess an appropriate delay to find the vsync. | ||
2039 | * This might not work on every machine. | ||
2040 | * | ||
2041 | * martin_rogge @ ki.maus.de, 8th Aug 1995 | ||
2042 | */ | ||
2043 | |||
2044 | #define LINE_DELAY (mono_moni ? 30 : 70) | ||
2045 | #define SYNC_DELAY (mono_moni ? 1500 : 2000) | ||
2046 | |||
2047 | /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */ | ||
2048 | static void st_ovsc_switch(void) | ||
2049 | { | ||
2050 | unsigned long flags; | ||
2051 | register unsigned char old, new; | ||
2052 | |||
2053 | if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) | ||
2054 | return; | ||
2055 | local_irq_save(flags); | ||
2056 | |||
2057 | mfp.tim_ct_b = 0x10; | ||
2058 | mfp.active_edge |= 8; | ||
2059 | mfp.tim_ct_b = 0; | ||
2060 | mfp.tim_dt_b = 0xf0; | ||
2061 | mfp.tim_ct_b = 8; | ||
2062 | while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ | ||
2063 | ; | ||
2064 | new = mfp.tim_dt_b; | ||
2065 | do { | ||
2066 | udelay(LINE_DELAY); | ||
2067 | old = new; | ||
2068 | new = mfp.tim_dt_b; | ||
2069 | } while (old != new); | ||
2070 | mfp.tim_ct_b = 0x10; | ||
2071 | udelay(SYNC_DELAY); | ||
2072 | |||
2073 | if (atari_switches & ATARI_SWITCH_OVSC_IKBD) | ||
2074 | acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE; | ||
2075 | if (atari_switches & ATARI_SWITCH_OVSC_MIDI) | ||
2076 | acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; | ||
2077 | if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) { | ||
2078 | sound_ym.rd_data_reg_sel = 14; | ||
2079 | sound_ym.wd_data = sound_ym.rd_data_reg_sel | | ||
2080 | ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | | ||
2081 | ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0); | ||
2082 | } | ||
2083 | local_irq_restore(flags); | ||
2084 | } | ||
2085 | |||
2086 | /* ------------------- External Video ---------------------- */ | ||
2087 | |||
2088 | #ifdef ATAFB_EXT | ||
2089 | |||
2090 | static int ext_encode_fix( struct fb_fix_screeninfo *fix, | ||
2091 | struct atafb_par *par ) | ||
2092 | |||
2093 | { | ||
2094 | strcpy(fix->id,"Unknown Extern"); | ||
2095 | fix->smem_start = (unsigned long)external_addr; | ||
2096 | fix->smem_len = PAGE_ALIGN(external_len); | ||
2097 | if (external_depth == 1) { | ||
2098 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
2099 | /* The letters 'n' and 'i' in the "atavideo=external:" stand | ||
2100 | * for "normal" and "inverted", rsp., in the monochrome case */ | ||
2101 | fix->visual = | ||
2102 | (external_pmode == FB_TYPE_INTERLEAVED_PLANES || | ||
2103 | external_pmode == FB_TYPE_PACKED_PIXELS) ? | ||
2104 | FB_VISUAL_MONO10 : | ||
2105 | FB_VISUAL_MONO01; | ||
2106 | } | ||
2107 | else { | ||
2108 | /* Use STATIC if we don't know how to access color registers */ | ||
2109 | int visual = external_vgaiobase ? | ||
2110 | FB_VISUAL_PSEUDOCOLOR : | ||
2111 | FB_VISUAL_STATIC_PSEUDOCOLOR; | ||
2112 | switch (external_pmode) { | ||
2113 | case -1: /* truecolor */ | ||
2114 | fix->type=FB_TYPE_PACKED_PIXELS; | ||
2115 | fix->visual=FB_VISUAL_TRUECOLOR; | ||
2116 | break; | ||
2117 | case FB_TYPE_PACKED_PIXELS: | ||
2118 | fix->type=FB_TYPE_PACKED_PIXELS; | ||
2119 | fix->visual=visual; | ||
2120 | break; | ||
2121 | case FB_TYPE_PLANES: | ||
2122 | fix->type=FB_TYPE_PLANES; | ||
2123 | fix->visual=visual; | ||
2124 | break; | ||
2125 | case FB_TYPE_INTERLEAVED_PLANES: | ||
2126 | fix->type=FB_TYPE_INTERLEAVED_PLANES; | ||
2127 | fix->type_aux=2; | ||
2128 | fix->visual=visual; | ||
2129 | break; | ||
2130 | } | ||
2131 | } | ||
2132 | fix->xpanstep = 0; | ||
2133 | fix->ypanstep = 0; | ||
2134 | fix->ywrapstep = 0; | ||
2135 | fix->line_length = 0; | ||
2136 | return 0; | ||
2137 | } | ||
2138 | |||
2139 | |||
2140 | static int ext_decode_var( struct fb_var_screeninfo *var, | ||
2141 | struct atafb_par *par ) | ||
2142 | { | ||
2143 | struct fb_var_screeninfo *myvar = &atafb_predefined[0]; | ||
2144 | |||
2145 | if (var->bits_per_pixel > myvar->bits_per_pixel || | ||
2146 | var->xres > myvar->xres || | ||
2147 | var->xres_virtual > myvar->xres_virtual || | ||
2148 | var->yres > myvar->yres || | ||
2149 | var->xoffset > 0 || | ||
2150 | var->yoffset > 0) | ||
2151 | return -EINVAL; | ||
2152 | return 0; | ||
2153 | } | ||
2154 | |||
2155 | |||
2156 | static int ext_encode_var( struct fb_var_screeninfo *var, | ||
2157 | struct atafb_par *par ) | ||
2158 | { | ||
2159 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
2160 | var->red.offset=0; | ||
2161 | var->red.length=(external_pmode == -1) ? external_depth/3 : | ||
2162 | (external_vgaiobase ? external_bitspercol : 0); | ||
2163 | var->red.msb_right=0; | ||
2164 | var->grayscale=0; | ||
2165 | |||
2166 | var->pixclock=31041; | ||
2167 | var->left_margin=120; /* these are surely incorrect */ | ||
2168 | var->right_margin=100; | ||
2169 | var->upper_margin=8; | ||
2170 | var->lower_margin=16; | ||
2171 | var->hsync_len=140; | ||
2172 | var->vsync_len=30; | ||
2173 | |||
2174 | var->height=-1; | ||
2175 | var->width=-1; | ||
2176 | |||
2177 | var->sync=0; | ||
2178 | |||
2179 | var->xres = external_xres; | ||
2180 | var->yres = external_yres; | ||
2181 | var->xres_virtual = external_xres_virtual; | ||
2182 | var->bits_per_pixel = external_depth; | ||
2183 | |||
2184 | var->blue=var->green=var->red; | ||
2185 | var->transp.offset=0; | ||
2186 | var->transp.length=0; | ||
2187 | var->transp.msb_right=0; | ||
2188 | var->yres_virtual=var->yres; | ||
2189 | var->xoffset=0; | ||
2190 | var->yoffset=0; | ||
2191 | var->nonstd=0; | ||
2192 | var->activate=0; | ||
2193 | var->vmode=FB_VMODE_NONINTERLACED; | ||
2194 | return 0; | ||
2195 | } | ||
2196 | |||
2197 | |||
2198 | static void ext_get_par( struct atafb_par *par ) | ||
2199 | { | ||
2200 | par->screen_base = external_addr; | ||
2201 | } | ||
2202 | |||
2203 | static void ext_set_par( struct atafb_par *par ) | ||
2204 | { | ||
2205 | } | ||
2206 | |||
2207 | #define OUTB(port,val) \ | ||
2208 | *((unsigned volatile char *) ((port)+external_vgaiobase))=(val) | ||
2209 | #define INB(port) \ | ||
2210 | (*((unsigned volatile char *) ((port)+external_vgaiobase))) | ||
2211 | #define DACDelay \ | ||
2212 | do { \ | ||
2213 | unsigned char tmp=INB(0x3da); \ | ||
2214 | tmp=INB(0x3da); \ | ||
2215 | } while (0) | ||
2216 | |||
2217 | static int ext_getcolreg( unsigned regno, unsigned *red, | ||
2218 | unsigned *green, unsigned *blue, | ||
2219 | unsigned *transp, struct fb_info *info ) | ||
2220 | { | ||
2221 | if (! external_vgaiobase) | ||
2222 | return 1; | ||
2223 | |||
2224 | *red = ext_color[regno].red; | ||
2225 | *green = ext_color[regno].green; | ||
2226 | *blue = ext_color[regno].blue; | ||
2227 | *transp=0; | ||
2228 | return 0; | ||
2229 | } | ||
2230 | |||
2231 | static int ext_setcolreg( unsigned regno, unsigned red, | ||
2232 | unsigned green, unsigned blue, | ||
2233 | unsigned transp, struct fb_info *info ) | ||
2234 | |||
2235 | { unsigned char colmask = (1 << external_bitspercol) - 1; | ||
2236 | |||
2237 | if (! external_vgaiobase) | ||
2238 | return 1; | ||
2239 | |||
2240 | ext_color[regno].red = red; | ||
2241 | ext_color[regno].green = green; | ||
2242 | ext_color[regno].blue = blue; | ||
2243 | |||
2244 | switch (external_card_type) { | ||
2245 | case IS_VGA: | ||
2246 | OUTB(0x3c8, regno); | ||
2247 | DACDelay; | ||
2248 | OUTB(0x3c9, red & colmask); | ||
2249 | DACDelay; | ||
2250 | OUTB(0x3c9, green & colmask); | ||
2251 | DACDelay; | ||
2252 | OUTB(0x3c9, blue & colmask); | ||
2253 | DACDelay; | ||
2254 | return 0; | ||
2255 | |||
2256 | case IS_MV300: | ||
2257 | OUTB((MV300_reg[regno] << 2)+1, red); | ||
2258 | OUTB((MV300_reg[regno] << 2)+1, green); | ||
2259 | OUTB((MV300_reg[regno] << 2)+1, blue); | ||
2260 | return 0; | ||
2261 | |||
2262 | default: | ||
2263 | return 1; | ||
2264 | } | ||
2265 | } | ||
2266 | |||
2267 | |||
2268 | static int ext_detect( void ) | ||
2269 | |||
2270 | { | ||
2271 | struct fb_var_screeninfo *myvar = &atafb_predefined[0]; | ||
2272 | struct atafb_par dummy_par; | ||
2273 | |||
2274 | myvar->xres = external_xres; | ||
2275 | myvar->xres_virtual = external_xres_virtual; | ||
2276 | myvar->yres = external_yres; | ||
2277 | myvar->bits_per_pixel = external_depth; | ||
2278 | ext_encode_var(myvar, &dummy_par); | ||
2279 | return 1; | ||
2280 | } | ||
2281 | |||
2282 | #endif /* ATAFB_EXT */ | ||
2283 | |||
2284 | /* ------ This is the same for most hardware types -------- */ | ||
2285 | |||
2286 | static void set_screen_base(void *s_base) | ||
2287 | { | ||
2288 | unsigned long addr; | ||
2289 | addr= virt_to_phys(s_base); | ||
2290 | /* Setup Screen Memory */ | ||
2291 | shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); | ||
2292 | shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); | ||
2293 | shifter.bas_lo=(unsigned char) (addr & 0x0000ff); | ||
2294 | } | ||
2295 | |||
2296 | |||
2297 | static int pan_display( struct fb_var_screeninfo *var, | ||
2298 | struct atafb_par *par ) | ||
2299 | { | ||
2300 | if (!fbhw->set_screen_base || | ||
2301 | (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) | ||
2302 | return -EINVAL; | ||
2303 | var->xoffset = up(var->xoffset, 16); | ||
2304 | par->screen_base = screen_base + | ||
2305 | (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset) | ||
2306 | * fb_display[fb_info.currcon].var.bits_per_pixel / 8; | ||
2307 | fbhw->set_screen_base (par->screen_base); | ||
2308 | return 0; | ||
2309 | } | ||
2310 | |||
2311 | |||
2312 | /* ------------ Interfaces to hardware functions ------------ */ | ||
2313 | |||
2314 | |||
2315 | #ifdef ATAFB_TT | ||
2316 | static struct fb_hwswitch tt_switch = { | ||
2317 | tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, | ||
2318 | tt_get_par, tt_set_par, tt_getcolreg, | ||
2319 | set_screen_base, NULL, pan_display | ||
2320 | }; | ||
2321 | #endif | ||
2322 | |||
2323 | #ifdef ATAFB_FALCON | ||
2324 | static struct fb_hwswitch falcon_switch = { | ||
2325 | falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, | ||
2326 | falcon_get_par, falcon_set_par, falcon_getcolreg, | ||
2327 | set_screen_base, falcon_blank, falcon_pan_display | ||
2328 | }; | ||
2329 | #endif | ||
2330 | |||
2331 | #ifdef ATAFB_STE | ||
2332 | static struct fb_hwswitch st_switch = { | ||
2333 | stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, | ||
2334 | stste_get_par, stste_set_par, stste_getcolreg, | ||
2335 | stste_set_screen_base, NULL, pan_display | ||
2336 | }; | ||
2337 | #endif | ||
2338 | |||
2339 | #ifdef ATAFB_EXT | ||
2340 | static struct fb_hwswitch ext_switch = { | ||
2341 | ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, | ||
2342 | ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL | ||
2343 | }; | ||
2344 | #endif | ||
2345 | |||
2346 | |||
2347 | |||
2348 | static void atafb_get_par( struct atafb_par *par ) | ||
2349 | { | ||
2350 | if (current_par_valid) { | ||
2351 | *par=current_par; | ||
2352 | } | ||
2353 | else | ||
2354 | fbhw->get_par(par); | ||
2355 | } | ||
2356 | |||
2357 | |||
2358 | static void atafb_set_par( struct atafb_par *par ) | ||
2359 | { | ||
2360 | fbhw->set_par(par); | ||
2361 | current_par=*par; | ||
2362 | current_par_valid=1; | ||
2363 | } | ||
2364 | |||
2365 | |||
2366 | |||
2367 | /* =========================================================== */ | ||
2368 | /* ============== Hardware Independent Functions ============= */ | ||
2369 | /* =========================================================== */ | ||
2370 | |||
2371 | |||
2372 | /* used for hardware scrolling */ | ||
2373 | |||
2374 | static int | ||
2375 | fb_update_var(int con, struct fb_info *info) | ||
2376 | { | ||
2377 | int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual* | ||
2378 | fb_display[con].var.bits_per_pixel>>3; | ||
2379 | |||
2380 | current_par.screen_base=screen_base + off; | ||
2381 | |||
2382 | if (fbhw->set_screen_base) | ||
2383 | fbhw->set_screen_base(current_par.screen_base); | ||
2384 | return 0; | ||
2385 | } | ||
2386 | |||
2387 | static int | ||
2388 | do_fb_set_var(struct fb_var_screeninfo *var, int isactive) | ||
2389 | { | ||
2390 | int err,activate; | ||
2391 | struct atafb_par par; | ||
2392 | if ((err=fbhw->decode_var(var, &par))) | ||
2393 | return err; | ||
2394 | activate=var->activate; | ||
2395 | if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) | ||
2396 | atafb_set_par(&par); | ||
2397 | fbhw->encode_var(var, &par); | ||
2398 | var->activate=activate; | ||
2399 | return 0; | ||
2400 | } | ||
2401 | |||
2402 | static int | ||
2403 | atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) | ||
2404 | { | ||
2405 | struct atafb_par par; | ||
2406 | if (con == -1) | ||
2407 | atafb_get_par(&par); | ||
2408 | else { | ||
2409 | int err; | ||
2410 | if ((err=fbhw->decode_var(&fb_display[con].var,&par))) | ||
2411 | return err; | ||
2412 | } | ||
2413 | memset(fix, 0, sizeof(struct fb_fix_screeninfo)); | ||
2414 | return fbhw->encode_fix(fix, &par); | ||
2415 | } | ||
2416 | |||
2417 | static int | ||
2418 | atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) | ||
2419 | { | ||
2420 | struct atafb_par par; | ||
2421 | if (con == -1) { | ||
2422 | atafb_get_par(&par); | ||
2423 | fbhw->encode_var(var, &par); | ||
2424 | } | ||
2425 | else | ||
2426 | *var=fb_display[con].var; | ||
2427 | return 0; | ||
2428 | } | ||
2429 | |||
2430 | static void | ||
2431 | atafb_set_disp(int con, struct fb_info *info) | ||
2432 | { | ||
2433 | struct fb_fix_screeninfo fix; | ||
2434 | struct fb_var_screeninfo var; | ||
2435 | struct display *display; | ||
2436 | |||
2437 | if (con >= 0) | ||
2438 | display = &fb_display[con]; | ||
2439 | else | ||
2440 | display = &disp; /* used during initialization */ | ||
2441 | |||
2442 | atafb_get_fix(&fix, con, info); | ||
2443 | atafb_get_var(&var, con, info); | ||
2444 | if (con == -1) | ||
2445 | con=0; | ||
2446 | info->screen_base = (void *)fix.smem_start; | ||
2447 | display->visual = fix.visual; | ||
2448 | display->type = fix.type; | ||
2449 | display->type_aux = fix.type_aux; | ||
2450 | display->ypanstep = fix.ypanstep; | ||
2451 | display->ywrapstep = fix.ywrapstep; | ||
2452 | display->line_length = fix.line_length; | ||
2453 | if (fix.visual != FB_VISUAL_PSEUDOCOLOR && | ||
2454 | fix.visual != FB_VISUAL_DIRECTCOLOR) | ||
2455 | display->can_soft_blank = 0; | ||
2456 | else | ||
2457 | display->can_soft_blank = 1; | ||
2458 | display->inverse = | ||
2459 | (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); | ||
2460 | switch (fix.type) { | ||
2461 | case FB_TYPE_INTERLEAVED_PLANES: | ||
2462 | switch (var.bits_per_pixel) { | ||
2463 | #ifdef FBCON_HAS_IPLAN2P2 | ||
2464 | case 2: | ||
2465 | display->dispsw = &fbcon_iplan2p2; | ||
2466 | break; | ||
2467 | #endif | ||
2468 | #ifdef FBCON_HAS_IPLAN2P4 | ||
2469 | case 4: | ||
2470 | display->dispsw = &fbcon_iplan2p4; | ||
2471 | break; | ||
2472 | #endif | ||
2473 | #ifdef FBCON_HAS_IPLAN2P8 | ||
2474 | case 8: | ||
2475 | display->dispsw = &fbcon_iplan2p8; | ||
2476 | break; | ||
2477 | #endif | ||
2478 | } | ||
2479 | break; | ||
2480 | case FB_TYPE_PACKED_PIXELS: | ||
2481 | switch (var.bits_per_pixel) { | ||
2482 | #ifdef FBCON_HAS_MFB | ||
2483 | case 1: | ||
2484 | display->dispsw = &fbcon_mfb; | ||
2485 | break; | ||
2486 | #endif | ||
2487 | #ifdef FBCON_HAS_CFB8 | ||
2488 | case 8: | ||
2489 | display->dispsw = &fbcon_cfb8; | ||
2490 | break; | ||
2491 | #endif | ||
2492 | #ifdef FBCON_HAS_CFB16 | ||
2493 | case 16: | ||
2494 | display->dispsw = &fbcon_cfb16; | ||
2495 | display->dispsw_data = fbcon_cfb16_cmap; | ||
2496 | break; | ||
2497 | #endif | ||
2498 | } | ||
2499 | break; | ||
2500 | } | ||
2501 | } | ||
2502 | |||
2503 | static int | ||
2504 | atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) | ||
2505 | { | ||
2506 | int err,oldxres,oldyres,oldbpp,oldxres_virtual, | ||
2507 | oldyres_virtual,oldyoffset; | ||
2508 | if ((err=do_fb_set_var(var, con==info->currcon))) | ||
2509 | return err; | ||
2510 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { | ||
2511 | oldxres=fb_display[con].var.xres; | ||
2512 | oldyres=fb_display[con].var.yres; | ||
2513 | oldxres_virtual=fb_display[con].var.xres_virtual; | ||
2514 | oldyres_virtual=fb_display[con].var.yres_virtual; | ||
2515 | oldbpp=fb_display[con].var.bits_per_pixel; | ||
2516 | oldyoffset=fb_display[con].var.yoffset; | ||
2517 | fb_display[con].var=*var; | ||
2518 | if (oldxres != var->xres || oldyres != var->yres | ||
2519 | || oldxres_virtual != var->xres_virtual | ||
2520 | || oldyres_virtual != var->yres_virtual | ||
2521 | || oldbpp != var->bits_per_pixel | ||
2522 | || oldyoffset != var->yoffset) { | ||
2523 | atafb_set_disp(con, info); | ||
2524 | (*fb_info.changevar)(con); | ||
2525 | fb_alloc_cmap(&fb_display[con].cmap, 0, 0); | ||
2526 | do_install_cmap(con, info); | ||
2527 | } | ||
2528 | } | ||
2529 | var->activate=0; | ||
2530 | return 0; | ||
2531 | } | ||
2532 | |||
2533 | |||
2534 | |||
2535 | static int | ||
2536 | atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) | ||
2537 | { | ||
2538 | if (con == info->currcon) /* current console ? */ | ||
2539 | return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); | ||
2540 | else | ||
2541 | if (fb_display[con].cmap.len) /* non default colormap ? */ | ||
2542 | fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); | ||
2543 | else | ||
2544 | fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), | ||
2545 | cmap, kspc ? 0 : 2); | ||
2546 | return 0; | ||
2547 | } | ||
2548 | |||
2549 | static int | ||
2550 | atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) | ||
2551 | { | ||
2552 | int xoffset = var->xoffset; | ||
2553 | int yoffset = var->yoffset; | ||
2554 | int err; | ||
2555 | |||
2556 | if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual | ||
2557 | || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) | ||
2558 | return -EINVAL; | ||
2559 | |||
2560 | if (con == info->currcon) { | ||
2561 | if (fbhw->pan_display) { | ||
2562 | if ((err = fbhw->pan_display(var, ¤t_par))) | ||
2563 | return err; | ||
2564 | } | ||
2565 | else | ||
2566 | return -EINVAL; | ||
2567 | } | ||
2568 | fb_display[con].var.xoffset = var->xoffset; | ||
2569 | fb_display[con].var.yoffset = var->yoffset; | ||
2570 | return 0; | ||
2571 | } | ||
2572 | |||
2573 | static int | ||
2574 | atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
2575 | unsigned long arg, int con, struct fb_info *info) | ||
2576 | { | ||
2577 | switch (cmd) { | ||
2578 | #ifdef FBCMD_GET_CURRENTPAR | ||
2579 | case FBCMD_GET_CURRENTPAR: | ||
2580 | if (copy_to_user((void *)arg, (void *)¤t_par, | ||
2581 | sizeof(struct atafb_par))) | ||
2582 | return -EFAULT; | ||
2583 | return 0; | ||
2584 | #endif | ||
2585 | #ifdef FBCMD_SET_CURRENTPAR | ||
2586 | case FBCMD_SET_CURRENTPAR: | ||
2587 | if (copy_from_user((void *)¤t_par, (void *)arg, | ||
2588 | sizeof(struct atafb_par))) | ||
2589 | return -EFAULT; | ||
2590 | atafb_set_par(¤t_par); | ||
2591 | return 0; | ||
2592 | #endif | ||
2593 | } | ||
2594 | return -EINVAL; | ||
2595 | } | ||
2596 | |||
2597 | /* (un)blank/poweroff | ||
2598 | * 0 = unblank | ||
2599 | * 1 = blank | ||
2600 | * 2 = suspend vsync | ||
2601 | * 3 = suspend hsync | ||
2602 | * 4 = off | ||
2603 | */ | ||
2604 | static int | ||
2605 | atafb_blank(int blank, struct fb_info *info) | ||
2606 | { | ||
2607 | unsigned short black[16]; | ||
2608 | struct fb_cmap cmap; | ||
2609 | if (fbhw->blank && !fbhw->blank(blank)) | ||
2610 | return 1; | ||
2611 | if (blank) { | ||
2612 | memset(black, 0, 16*sizeof(unsigned short)); | ||
2613 | cmap.red=black; | ||
2614 | cmap.green=black; | ||
2615 | cmap.blue=black; | ||
2616 | cmap.transp=NULL; | ||
2617 | cmap.start=0; | ||
2618 | cmap.len=16; | ||
2619 | fb_set_cmap(&cmap, 1, info); | ||
2620 | } | ||
2621 | else | ||
2622 | do_install_cmap(info->currcon, info); | ||
2623 | return 0; | ||
2624 | } | ||
2625 | |||
2626 | static struct fb_ops atafb_ops = { | ||
2627 | .owner = THIS_MODULE, | ||
2628 | .fb_get_fix = atafb_get_fix, | ||
2629 | .fb_get_var = atafb_get_var, | ||
2630 | .fb_set_var = atafb_set_var, | ||
2631 | .fb_get_cmap = atafb_get_cmap, | ||
2632 | .fb_set_cmap = gen_set_cmap, | ||
2633 | .fb_pan_display =atafb_pan_display, | ||
2634 | .fb_blank = atafb_blank, | ||
2635 | .fb_ioctl = atafb_ioctl, | ||
2636 | }; | ||
2637 | |||
2638 | static void | ||
2639 | check_default_par( int detected_mode ) | ||
2640 | { | ||
2641 | char default_name[10]; | ||
2642 | int i; | ||
2643 | struct fb_var_screeninfo var; | ||
2644 | unsigned long min_mem; | ||
2645 | |||
2646 | /* First try the user supplied mode */ | ||
2647 | if (default_par) { | ||
2648 | var=atafb_predefined[default_par-1]; | ||
2649 | var.activate = FB_ACTIVATE_TEST; | ||
2650 | if (do_fb_set_var(&var,1)) | ||
2651 | default_par=0; /* failed */ | ||
2652 | } | ||
2653 | /* Next is the autodetected one */ | ||
2654 | if (! default_par) { | ||
2655 | var=atafb_predefined[detected_mode-1]; /* autodetect */ | ||
2656 | var.activate = FB_ACTIVATE_TEST; | ||
2657 | if (!do_fb_set_var(&var,1)) | ||
2658 | default_par=detected_mode; | ||
2659 | } | ||
2660 | /* If that also failed, try some default modes... */ | ||
2661 | if (! default_par) { | ||
2662 | /* try default1, default2... */ | ||
2663 | for (i=1 ; i < 10 ; i++) { | ||
2664 | sprintf(default_name,"default%d",i); | ||
2665 | default_par=get_video_mode(default_name); | ||
2666 | if (! default_par) | ||
2667 | panic("can't set default video mode"); | ||
2668 | var=atafb_predefined[default_par-1]; | ||
2669 | var.activate = FB_ACTIVATE_TEST; | ||
2670 | if (! do_fb_set_var(&var,1)) | ||
2671 | break; /* ok */ | ||
2672 | } | ||
2673 | } | ||
2674 | min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8; | ||
2675 | if (default_mem_req < min_mem) | ||
2676 | default_mem_req=min_mem; | ||
2677 | } | ||
2678 | |||
2679 | static int | ||
2680 | atafb_switch(int con, struct fb_info *info) | ||
2681 | { | ||
2682 | /* Do we have to save the colormap ? */ | ||
2683 | if (fb_display[info->currcon].cmap.len) | ||
2684 | fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg, | ||
2685 | info); | ||
2686 | do_fb_set_var(&fb_display[con].var,1); | ||
2687 | info->currcon=con; | ||
2688 | /* Install new colormap */ | ||
2689 | do_install_cmap(con, info); | ||
2690 | return 0; | ||
2691 | } | ||
2692 | |||
2693 | int __init atafb_init(void) | ||
2694 | { | ||
2695 | int pad; | ||
2696 | int detected_mode; | ||
2697 | unsigned long mem_req; | ||
2698 | |||
2699 | if (!MACH_IS_ATARI) | ||
2700 | return -ENXIO; | ||
2701 | |||
2702 | do { | ||
2703 | #ifdef ATAFB_EXT | ||
2704 | if (external_addr) { | ||
2705 | fbhw = &ext_switch; | ||
2706 | atafb_ops.fb_setcolreg = &ext_setcolreg; | ||
2707 | break; | ||
2708 | } | ||
2709 | #endif | ||
2710 | #ifdef ATAFB_TT | ||
2711 | if (ATARIHW_PRESENT(TT_SHIFTER)) { | ||
2712 | fbhw = &tt_switch; | ||
2713 | atafb_ops.fb_setcolreg = &tt_setcolreg; | ||
2714 | break; | ||
2715 | } | ||
2716 | #endif | ||
2717 | #ifdef ATAFB_FALCON | ||
2718 | if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { | ||
2719 | fbhw = &falcon_switch; | ||
2720 | atafb_ops.fb_setcolreg = &falcon_setcolreg; | ||
2721 | request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, | ||
2722 | "framebuffer/modeswitch", falcon_vbl_switcher); | ||
2723 | break; | ||
2724 | } | ||
2725 | #endif | ||
2726 | #ifdef ATAFB_STE | ||
2727 | if (ATARIHW_PRESENT(STND_SHIFTER) || | ||
2728 | ATARIHW_PRESENT(EXTD_SHIFTER)) { | ||
2729 | fbhw = &st_switch; | ||
2730 | atafb_ops.fb_setcolreg = &stste_setcolreg; | ||
2731 | break; | ||
2732 | } | ||
2733 | fbhw = &st_switch; | ||
2734 | atafb_ops.fb_setcolreg = &stste_setcolreg; | ||
2735 | printk("Cannot determine video hardware; defaulting to ST(e)\n"); | ||
2736 | #else /* ATAFB_STE */ | ||
2737 | /* no default driver included */ | ||
2738 | /* Nobody will ever see this message :-) */ | ||
2739 | panic("Cannot initialize video hardware"); | ||
2740 | #endif | ||
2741 | } while (0); | ||
2742 | |||
2743 | /* Multisync monitor capabilities */ | ||
2744 | /* Atari-TOS defaults if no boot option present */ | ||
2745 | if (fb_info.monspecs.hfmin == 0) { | ||
2746 | fb_info.monspecs.hfmin = 31000; | ||
2747 | fb_info.monspecs.hfmax = 32000; | ||
2748 | fb_info.monspecs.vfmin = 58; | ||
2749 | fb_info.monspecs.vfmax = 62; | ||
2750 | } | ||
2751 | |||
2752 | detected_mode = fbhw->detect(); | ||
2753 | check_default_par(detected_mode); | ||
2754 | #ifdef ATAFB_EXT | ||
2755 | if (!external_addr) { | ||
2756 | #endif /* ATAFB_EXT */ | ||
2757 | mem_req = default_mem_req + ovsc_offset + ovsc_addlen; | ||
2758 | mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; | ||
2759 | screen_base = atari_stram_alloc(mem_req, "atafb"); | ||
2760 | if (!screen_base) | ||
2761 | panic("Cannot allocate screen memory"); | ||
2762 | memset(screen_base, 0, mem_req); | ||
2763 | pad = -(unsigned long)screen_base & (PAGE_SIZE-1); | ||
2764 | screen_base+=pad; | ||
2765 | real_screen_base=screen_base+ovsc_offset; | ||
2766 | screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; | ||
2767 | st_ovsc_switch(); | ||
2768 | if (CPU_IS_040_OR_060) { | ||
2769 | /* On a '040+, the cache mode of video RAM must be set to | ||
2770 | * write-through also for internal video hardware! */ | ||
2771 | cache_push(virt_to_phys(screen_base), screen_len); | ||
2772 | kernel_set_cachemode(screen_base, screen_len, | ||
2773 | IOMAP_WRITETHROUGH); | ||
2774 | } | ||
2775 | #ifdef ATAFB_EXT | ||
2776 | } | ||
2777 | else { | ||
2778 | /* Map the video memory (physical address given) to somewhere | ||
2779 | * in the kernel address space. | ||
2780 | */ | ||
2781 | external_addr = | ||
2782 | ioremap_writethrough((unsigned long)external_addr, | ||
2783 | external_len); | ||
2784 | if (external_vgaiobase) | ||
2785 | external_vgaiobase = | ||
2786 | (unsigned long)ioremap(external_vgaiobase, 0x10000); | ||
2787 | screen_base = | ||
2788 | real_screen_base = external_addr; | ||
2789 | screen_len = external_len & PAGE_MASK; | ||
2790 | memset (screen_base, 0, external_len); | ||
2791 | } | ||
2792 | #endif /* ATAFB_EXT */ | ||
2793 | |||
2794 | strcpy(fb_info.modename, "Atari Builtin "); | ||
2795 | fb_info.changevar = NULL; | ||
2796 | fb_info.fbops = &atafb_ops; | ||
2797 | fb_info.disp = &disp; | ||
2798 | fb_info.currcon = -1; | ||
2799 | fb_info.switch_con = &atafb_switch; | ||
2800 | fb_info.updatevar = &fb_update_var; | ||
2801 | fb_info.flags = FBINFO_FLAG_DEFAULT; | ||
2802 | do_fb_set_var(&atafb_predefined[default_par-1], 1); | ||
2803 | strcat(fb_info.modename, fb_var_names[default_par-1][0]); | ||
2804 | |||
2805 | atafb_get_var(&disp.var, -1, &fb_info); | ||
2806 | atafb_set_disp(-1, &fb_info); | ||
2807 | do_install_cmap(0, &fb_info); | ||
2808 | |||
2809 | if (register_framebuffer(&fb_info) < 0) | ||
2810 | return -EINVAL; | ||
2811 | |||
2812 | printk("Determined %dx%d, depth %d\n", | ||
2813 | disp.var.xres, disp.var.yres, disp.var.bits_per_pixel); | ||
2814 | if ((disp.var.xres != disp.var.xres_virtual) || | ||
2815 | (disp.var.yres != disp.var.yres_virtual)) | ||
2816 | printk(" virtual %dx%d\n", | ||
2817 | disp.var.xres_virtual, disp.var.yres_virtual); | ||
2818 | printk("fb%d: %s frame buffer device, using %dK of video memory\n", | ||
2819 | fb_info.node, fb_info.modename, screen_len>>10); | ||
2820 | |||
2821 | /* TODO: This driver cannot be unloaded yet */ | ||
2822 | return 0; | ||
2823 | } | ||
2824 | |||
2825 | |||
2826 | #ifdef ATAFB_EXT | ||
2827 | static void __init atafb_setup_ext(char *spec) | ||
2828 | { | ||
2829 | int xres, xres_virtual, yres, depth, planes; | ||
2830 | unsigned long addr, len; | ||
2831 | char *p; | ||
2832 | |||
2833 | /* Format is: <xres>;<yres>;<depth>;<plane organ.>; | ||
2834 | * <screen mem addr> | ||
2835 | * [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type> | ||
2836 | * [;<xres-virtual>]]]]] | ||
2837 | * | ||
2838 | * 09/23/97 Juergen | ||
2839 | * <xres_virtual>: hardware's x-resolution (f.e. ProMST) | ||
2840 | * | ||
2841 | * Even xres_virtual is available, we neither support panning nor hw-scrolling! | ||
2842 | */ | ||
2843 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2844 | return; | ||
2845 | xres_virtual = xres = simple_strtoul(p, NULL, 10); | ||
2846 | if (xres <= 0) | ||
2847 | return; | ||
2848 | |||
2849 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2850 | return; | ||
2851 | yres = simple_strtoul(p, NULL, 10); | ||
2852 | if (yres <= 0) | ||
2853 | return; | ||
2854 | |||
2855 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2856 | return; | ||
2857 | depth = simple_strtoul(p, NULL, 10); | ||
2858 | if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && | ||
2859 | depth != 16 && depth != 24) | ||
2860 | return; | ||
2861 | |||
2862 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2863 | return; | ||
2864 | if (*p == 'i') | ||
2865 | planes = FB_TYPE_INTERLEAVED_PLANES; | ||
2866 | else if (*p == 'p') | ||
2867 | planes = FB_TYPE_PACKED_PIXELS; | ||
2868 | else if (*p == 'n') | ||
2869 | planes = FB_TYPE_PLANES; | ||
2870 | else if (*p == 't') | ||
2871 | planes = -1; /* true color */ | ||
2872 | else | ||
2873 | return; | ||
2874 | |||
2875 | |||
2876 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2877 | return; | ||
2878 | addr = simple_strtoul(p, NULL, 0); | ||
2879 | |||
2880 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2881 | len = xres*yres*depth/8; | ||
2882 | else | ||
2883 | len = simple_strtoul(p, NULL, 0); | ||
2884 | |||
2885 | if ((p = strsep(&spec, ";")) && *p) { | ||
2886 | external_vgaiobase=simple_strtoul(p, NULL, 0); | ||
2887 | } | ||
2888 | |||
2889 | if ((p = strsep(&spec, ";")) && *p) { | ||
2890 | external_bitspercol = simple_strtoul(p, NULL, 0); | ||
2891 | if (external_bitspercol > 8) | ||
2892 | external_bitspercol = 8; | ||
2893 | else if (external_bitspercol < 1) | ||
2894 | external_bitspercol = 1; | ||
2895 | } | ||
2896 | |||
2897 | if ((p = strsep(&spec, ";")) && *p) { | ||
2898 | if (!strcmp(p, "vga")) | ||
2899 | external_card_type = IS_VGA; | ||
2900 | if (!strcmp(p, "mv300")) | ||
2901 | external_card_type = IS_MV300; | ||
2902 | } | ||
2903 | |||
2904 | if ((p = strsep(&spec, ";")) && *p) { | ||
2905 | xres_virtual = simple_strtoul(p, NULL, 10); | ||
2906 | if (xres_virtual < xres) | ||
2907 | xres_virtual = xres; | ||
2908 | if (xres_virtual*yres*depth/8 > len) | ||
2909 | len=xres_virtual*yres*depth/8; | ||
2910 | } | ||
2911 | |||
2912 | external_xres = xres; | ||
2913 | external_xres_virtual = xres_virtual; | ||
2914 | external_yres = yres; | ||
2915 | external_depth = depth; | ||
2916 | external_pmode = planes; | ||
2917 | external_addr = (void *)addr; | ||
2918 | external_len = len; | ||
2919 | |||
2920 | if (external_card_type == IS_MV300) | ||
2921 | switch (external_depth) { | ||
2922 | case 1: | ||
2923 | MV300_reg = MV300_reg_1bit; | ||
2924 | break; | ||
2925 | case 4: | ||
2926 | MV300_reg = MV300_reg_4bit; | ||
2927 | break; | ||
2928 | case 8: | ||
2929 | MV300_reg = MV300_reg_8bit; | ||
2930 | break; | ||
2931 | } | ||
2932 | } | ||
2933 | #endif /* ATAFB_EXT */ | ||
2934 | |||
2935 | |||
2936 | static void __init atafb_setup_int(char *spec) | ||
2937 | { | ||
2938 | /* Format to config extended internal video hardware like OverScan: | ||
2939 | "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>" | ||
2940 | Explanation: | ||
2941 | <xres>: x-resolution | ||
2942 | <yres>: y-resolution | ||
2943 | The following are only needed if you have an overscan which | ||
2944 | needs a black border: | ||
2945 | <xres_max>: max. length of a line in pixels your OverScan hardware would allow | ||
2946 | <yres_max>: max. number of lines your OverScan hardware would allow | ||
2947 | <offset>: Offset from physical beginning to visible beginning | ||
2948 | of screen in bytes | ||
2949 | */ | ||
2950 | int xres; | ||
2951 | char *p; | ||
2952 | |||
2953 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2954 | return; | ||
2955 | xres = simple_strtoul(p, NULL, 10); | ||
2956 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2957 | return; | ||
2958 | sttt_xres=xres; | ||
2959 | tt_yres=st_yres=simple_strtoul(p, NULL, 10); | ||
2960 | if ((p=strsep(&spec, ";")) && *p) { | ||
2961 | sttt_xres_virtual=simple_strtoul(p, NULL, 10); | ||
2962 | } | ||
2963 | if ((p=strsep(&spec, ";")) && *p) { | ||
2964 | sttt_yres_virtual=simple_strtoul(p, NULL, 0); | ||
2965 | } | ||
2966 | if ((p=strsep(&spec, ";")) && *p) { | ||
2967 | ovsc_offset=simple_strtoul(p, NULL, 0); | ||
2968 | } | ||
2969 | |||
2970 | if (ovsc_offset || (sttt_yres_virtual != st_yres)) | ||
2971 | use_hwscroll=0; | ||
2972 | } | ||
2973 | |||
2974 | |||
2975 | #ifdef ATAFB_FALCON | ||
2976 | static void __init atafb_setup_mcap(char *spec) | ||
2977 | { | ||
2978 | char *p; | ||
2979 | int vmin, vmax, hmin, hmax; | ||
2980 | |||
2981 | /* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax> | ||
2982 | * <V*> vertical freq. in Hz | ||
2983 | * <H*> horizontal freq. in kHz | ||
2984 | */ | ||
2985 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2986 | return; | ||
2987 | vmin = simple_strtoul(p, NULL, 10); | ||
2988 | if (vmin <= 0) | ||
2989 | return; | ||
2990 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2991 | return; | ||
2992 | vmax = simple_strtoul(p, NULL, 10); | ||
2993 | if (vmax <= 0 || vmax <= vmin) | ||
2994 | return; | ||
2995 | if (!(p = strsep(&spec, ";")) || !*p) | ||
2996 | return; | ||
2997 | hmin = 1000 * simple_strtoul(p, NULL, 10); | ||
2998 | if (hmin <= 0) | ||
2999 | return; | ||
3000 | if (!(p = strsep(&spec, "")) || !*p) | ||
3001 | return; | ||
3002 | hmax = 1000 * simple_strtoul(p, NULL, 10); | ||
3003 | if (hmax <= 0 || hmax <= hmin) | ||
3004 | return; | ||
3005 | |||
3006 | fb_info.monspecs.vfmin = vmin; | ||
3007 | fb_info.monspecs.vfmax = vmax; | ||
3008 | fb_info.monspecs.hfmin = hmin; | ||
3009 | fb_info.monspecs.hfmax = hmax; | ||
3010 | } | ||
3011 | #endif /* ATAFB_FALCON */ | ||
3012 | |||
3013 | |||
3014 | static void __init atafb_setup_user(char *spec) | ||
3015 | { | ||
3016 | /* Format of user defined video mode is: <xres>;<yres>;<depth> | ||
3017 | */ | ||
3018 | char *p; | ||
3019 | int xres, yres, depth, temp; | ||
3020 | |||
3021 | if (!(p = strsep(&spec, ";")) || !*p) | ||
3022 | return; | ||
3023 | xres = simple_strtoul(p, NULL, 10); | ||
3024 | if (!(p = strsep(&spec, ";")) || !*p) | ||
3025 | return; | ||
3026 | yres = simple_strtoul(p, NULL, 10); | ||
3027 | if (!(p = strsep(&spec, "")) || !*p) | ||
3028 | return; | ||
3029 | depth = simple_strtoul(p, NULL, 10); | ||
3030 | if ((temp=get_video_mode("user0"))) { | ||
3031 | default_par=temp; | ||
3032 | atafb_predefined[default_par-1].xres = xres; | ||
3033 | atafb_predefined[default_par-1].yres = yres; | ||
3034 | atafb_predefined[default_par-1].bits_per_pixel = depth; | ||
3035 | } | ||
3036 | } | ||
3037 | |||
3038 | int __init atafb_setup( char *options ) | ||
3039 | { | ||
3040 | char *this_opt; | ||
3041 | int temp; | ||
3042 | |||
3043 | fb_info.fontname[0] = '\0'; | ||
3044 | |||
3045 | if (!options || !*options) | ||
3046 | return 0; | ||
3047 | |||
3048 | while ((this_opt = strsep(&options, ",")) != NULL) { | ||
3049 | if (!*this_opt) continue; | ||
3050 | if ((temp=get_video_mode(this_opt))) | ||
3051 | default_par=temp; | ||
3052 | else if (! strcmp(this_opt, "inverse")) | ||
3053 | inverse=1; | ||
3054 | else if (!strncmp(this_opt, "font:", 5)) | ||
3055 | strcpy(fb_info.fontname, this_opt+5); | ||
3056 | else if (! strncmp(this_opt, "hwscroll_",9)) { | ||
3057 | hwscroll=simple_strtoul(this_opt+9, NULL, 10); | ||
3058 | if (hwscroll < 0) | ||
3059 | hwscroll = 0; | ||
3060 | if (hwscroll > 200) | ||
3061 | hwscroll = 200; | ||
3062 | } | ||
3063 | #ifdef ATAFB_EXT | ||
3064 | else if (!strcmp(this_opt,"mv300")) { | ||
3065 | external_bitspercol = 8; | ||
3066 | external_card_type = IS_MV300; | ||
3067 | } | ||
3068 | else if (!strncmp(this_opt,"external:",9)) | ||
3069 | atafb_setup_ext(this_opt+9); | ||
3070 | #endif | ||
3071 | else if (!strncmp(this_opt,"internal:",9)) | ||
3072 | atafb_setup_int(this_opt+9); | ||
3073 | #ifdef ATAFB_FALCON | ||
3074 | else if (!strncmp(this_opt, "eclock:", 7)) { | ||
3075 | fext.f = simple_strtoul(this_opt+7, NULL, 10); | ||
3076 | /* external pixelclock in kHz --> ps */ | ||
3077 | fext.t = 1000000000/fext.f; | ||
3078 | fext.f *= 1000; | ||
3079 | } | ||
3080 | else if (!strncmp(this_opt, "monitorcap:", 11)) | ||
3081 | atafb_setup_mcap(this_opt+11); | ||
3082 | #endif | ||
3083 | else if (!strcmp(this_opt, "keep")) | ||
3084 | DontCalcRes = 1; | ||
3085 | else if (!strncmp(this_opt, "R", 1)) | ||
3086 | atafb_setup_user(this_opt+1); | ||
3087 | } | ||
3088 | return 0; | ||
3089 | } | ||
3090 | |||
3091 | #ifdef MODULE | ||
3092 | MODULE_LICENSE("GPL"); | ||
3093 | |||
3094 | int init_module(void) | ||
3095 | { | ||
3096 | return atafb_init(); | ||
3097 | } | ||
3098 | #endif /* MODULE */ | ||