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