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, ¤t_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(¤t_par, (void *)arg,
2586f7018c21STomi Valkeinen sizeof(struct atafb_par)))
2587f7018c21STomi Valkeinen return -EFAULT;
2588f7018c21STomi Valkeinen ata_set_par(¤t_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(¤t_par);
3107f7018c21STomi Valkeinen fb_info.par = ¤t_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