18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (C) 1994 Martin Schaller & Roman Hodek
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
78c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
88c2ecf20Sopenharmony_ci * for more details.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * History:
118c2ecf20Sopenharmony_ci *   - 03 Jan 95: Original version by Martin Schaller: The TT driver and
128c2ecf20Sopenharmony_ci *                all the device independent stuff
138c2ecf20Sopenharmony_ci *   - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch)
148c2ecf20Sopenharmony_ci *                and wrote the Falcon, ST(E), and External drivers
158c2ecf20Sopenharmony_ci *                based on the original TT driver.
168c2ecf20Sopenharmony_ci *   - 07 May 95: Martin: Added colormap operations for the external driver
178c2ecf20Sopenharmony_ci *   - 21 May 95: Martin: Added support for overscan
188c2ecf20Sopenharmony_ci *		  Andreas: some bug fixes for this
198c2ecf20Sopenharmony_ci *   -    Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>:
208c2ecf20Sopenharmony_ci *                Programmable Falcon video modes
218c2ecf20Sopenharmony_ci *                (thanks to Christian Cartus for documentation
228c2ecf20Sopenharmony_ci *                of VIDEL registers).
238c2ecf20Sopenharmony_ci *   - 27 Dec 95: Guenther: Implemented user definable video modes "user[0-7]"
248c2ecf20Sopenharmony_ci *                on minor 24...31. "user0" may be set on commandline by
258c2ecf20Sopenharmony_ci *                "R<x>;<y>;<depth>". (Makes sense only on Falcon)
268c2ecf20Sopenharmony_ci *                Video mode switch on Falcon now done at next VBL interrupt
278c2ecf20Sopenharmony_ci *                to avoid the annoying right shift of the screen.
288c2ecf20Sopenharmony_ci *   - 23 Sep 97: Juergen: added xres_virtual for cards like ProMST
298c2ecf20Sopenharmony_ci *                The external-part is legacy, therefore hardware-specific
308c2ecf20Sopenharmony_ci *                functions like panning/hardwarescrolling/blanking isn't
318c2ecf20Sopenharmony_ci *				  supported.
328c2ecf20Sopenharmony_ci *   - 29 Sep 97: Juergen: added Romans suggestion for pan_display
338c2ecf20Sopenharmony_ci *				  (var->xoffset was changed even if no set_screen_base avail.)
348c2ecf20Sopenharmony_ci *	 - 05 Oct 97: Juergen: extfb (PACKED_PIXEL) is FB_PSEUDOCOLOR 'cause
358c2ecf20Sopenharmony_ci *				  we know how to set the colors
368c2ecf20Sopenharmony_ci *				  ext_*palette: read from ext_colors (former MV300_colors)
378c2ecf20Sopenharmony_ci *							    write to ext_colors and RAMDAC
388c2ecf20Sopenharmony_ci *
398c2ecf20Sopenharmony_ci * To do:
408c2ecf20Sopenharmony_ci *   - For the Falcon it is not possible to set random video modes on
418c2ecf20Sopenharmony_ci *     SM124 and SC/TV, only the bootup resolution is supported.
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define ATAFB_TT
468c2ecf20Sopenharmony_ci#define ATAFB_STE
478c2ecf20Sopenharmony_ci#define ATAFB_EXT
488c2ecf20Sopenharmony_ci#define ATAFB_FALCON
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include <linux/kernel.h>
518c2ecf20Sopenharmony_ci#include <linux/errno.h>
528c2ecf20Sopenharmony_ci#include <linux/string.h>
538c2ecf20Sopenharmony_ci#include <linux/mm.h>
548c2ecf20Sopenharmony_ci#include <linux/delay.h>
558c2ecf20Sopenharmony_ci#include <linux/init.h>
568c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
578c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#include <asm/setup.h>
608c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
618c2ecf20Sopenharmony_ci#include <asm/irq.h>
628c2ecf20Sopenharmony_ci#include <asm/io.h>
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#include <asm/atarihw.h>
658c2ecf20Sopenharmony_ci#include <asm/atariints.h>
668c2ecf20Sopenharmony_ci#include <asm/atari_stram.h>
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#include <linux/fb.h>
698c2ecf20Sopenharmony_ci#include <asm/atarikb.h>
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#include "c2p.h"
728c2ecf20Sopenharmony_ci#include "atafb.h"
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define SWITCH_ACIA 0x01		/* modes for switch on OverScan */
758c2ecf20Sopenharmony_ci#define SWITCH_SND6 0x40
768c2ecf20Sopenharmony_ci#define SWITCH_SND7 0x80
778c2ecf20Sopenharmony_ci#define SWITCH_NONE 0x00
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int default_par;		/* default resolution (0=none) */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic unsigned long default_mem_req;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int hwscroll = -1;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int use_hwscroll = 1;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int sttt_xres = 640, st_yres = 400, tt_yres = 480;
918c2ecf20Sopenharmony_cistatic int sttt_xres_virtual = 640, sttt_yres_virtual = 400;
928c2ecf20Sopenharmony_cistatic int ovsc_offset, ovsc_addlen;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	/*
958c2ecf20Sopenharmony_ci	 * Hardware parameters for current mode
968c2ecf20Sopenharmony_ci	 */
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic struct atafb_par {
998c2ecf20Sopenharmony_ci	void *screen_base;
1008c2ecf20Sopenharmony_ci	int yres_virtual;
1018c2ecf20Sopenharmony_ci	u_long next_line;
1028c2ecf20Sopenharmony_ci#if defined ATAFB_TT || defined ATAFB_STE
1038c2ecf20Sopenharmony_ci	union {
1048c2ecf20Sopenharmony_ci		struct {
1058c2ecf20Sopenharmony_ci			int mode;
1068c2ecf20Sopenharmony_ci			int sync;
1078c2ecf20Sopenharmony_ci		} tt, st;
1088c2ecf20Sopenharmony_ci#endif
1098c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
1108c2ecf20Sopenharmony_ci		struct falcon_hw {
1118c2ecf20Sopenharmony_ci			/* Here are fields for storing a video mode, as direct
1128c2ecf20Sopenharmony_ci			 * parameters for the hardware.
1138c2ecf20Sopenharmony_ci			 */
1148c2ecf20Sopenharmony_ci			short sync;
1158c2ecf20Sopenharmony_ci			short line_width;
1168c2ecf20Sopenharmony_ci			short line_offset;
1178c2ecf20Sopenharmony_ci			short st_shift;
1188c2ecf20Sopenharmony_ci			short f_shift;
1198c2ecf20Sopenharmony_ci			short vid_control;
1208c2ecf20Sopenharmony_ci			short vid_mode;
1218c2ecf20Sopenharmony_ci			short xoffset;
1228c2ecf20Sopenharmony_ci			short hht, hbb, hbe, hdb, hde, hss;
1238c2ecf20Sopenharmony_ci			short vft, vbb, vbe, vdb, vde, vss;
1248c2ecf20Sopenharmony_ci			/* auxiliary information */
1258c2ecf20Sopenharmony_ci			short mono;
1268c2ecf20Sopenharmony_ci			short ste_mode;
1278c2ecf20Sopenharmony_ci			short bpp;
1288c2ecf20Sopenharmony_ci			u32 pseudo_palette[16];
1298c2ecf20Sopenharmony_ci		} falcon;
1308c2ecf20Sopenharmony_ci#endif
1318c2ecf20Sopenharmony_ci		/* Nothing needed for external mode */
1328c2ecf20Sopenharmony_ci	} hw;
1338c2ecf20Sopenharmony_ci} current_par;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/* Don't calculate an own resolution, and thus don't change the one found when
1368c2ecf20Sopenharmony_ci * booting (currently used for the Falcon to keep settings for internal video
1378c2ecf20Sopenharmony_ci * hardware extensions (e.g. ScreenBlaster)  */
1388c2ecf20Sopenharmony_cistatic int DontCalcRes = 0;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
1418c2ecf20Sopenharmony_ci#define HHT hw.falcon.hht
1428c2ecf20Sopenharmony_ci#define HBB hw.falcon.hbb
1438c2ecf20Sopenharmony_ci#define HBE hw.falcon.hbe
1448c2ecf20Sopenharmony_ci#define HDB hw.falcon.hdb
1458c2ecf20Sopenharmony_ci#define HDE hw.falcon.hde
1468c2ecf20Sopenharmony_ci#define HSS hw.falcon.hss
1478c2ecf20Sopenharmony_ci#define VFT hw.falcon.vft
1488c2ecf20Sopenharmony_ci#define VBB hw.falcon.vbb
1498c2ecf20Sopenharmony_ci#define VBE hw.falcon.vbe
1508c2ecf20Sopenharmony_ci#define VDB hw.falcon.vdb
1518c2ecf20Sopenharmony_ci#define VDE hw.falcon.vde
1528c2ecf20Sopenharmony_ci#define VSS hw.falcon.vss
1538c2ecf20Sopenharmony_ci#define VCO_CLOCK25		0x04
1548c2ecf20Sopenharmony_ci#define VCO_CSYPOS		0x10
1558c2ecf20Sopenharmony_ci#define VCO_VSYPOS		0x20
1568c2ecf20Sopenharmony_ci#define VCO_HSYPOS		0x40
1578c2ecf20Sopenharmony_ci#define VCO_SHORTOFFS	0x100
1588c2ecf20Sopenharmony_ci#define VMO_DOUBLE		0x01
1598c2ecf20Sopenharmony_ci#define VMO_INTER		0x02
1608c2ecf20Sopenharmony_ci#define VMO_PREMASK		0x0c
1618c2ecf20Sopenharmony_ci#endif
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic struct fb_info fb_info = {
1648c2ecf20Sopenharmony_ci	.fix = {
1658c2ecf20Sopenharmony_ci		.id	= "Atari ",
1668c2ecf20Sopenharmony_ci		.visual	= FB_VISUAL_PSEUDOCOLOR,
1678c2ecf20Sopenharmony_ci		.accel	= FB_ACCEL_NONE,
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void *screen_base;	/* base address of screen */
1728c2ecf20Sopenharmony_cistatic unsigned long phys_screen_base;	/* (only for Overscan) */
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int screen_len;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int current_par_valid;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int mono_moni;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/* external video handling */
1848c2ecf20Sopenharmony_cistatic unsigned int external_xres;
1858c2ecf20Sopenharmony_cistatic unsigned int external_xres_virtual;
1868c2ecf20Sopenharmony_cistatic unsigned int external_yres;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/*
1898c2ecf20Sopenharmony_ci * not needed - atafb will never support panning/hardwarescroll with external
1908c2ecf20Sopenharmony_ci * static unsigned int external_yres_virtual;
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_cistatic unsigned int external_depth;
1938c2ecf20Sopenharmony_cistatic int external_pmode;
1948c2ecf20Sopenharmony_cistatic void *external_screen_base;
1958c2ecf20Sopenharmony_cistatic unsigned long external_addr;
1968c2ecf20Sopenharmony_cistatic unsigned long external_len;
1978c2ecf20Sopenharmony_cistatic unsigned long external_vgaiobase;
1988c2ecf20Sopenharmony_cistatic unsigned int external_bitspercol = 6;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/*
2018c2ecf20Sopenharmony_ci * JOE <joe@amber.dinoco.de>:
2028c2ecf20Sopenharmony_ci * added card type for external driver, is only needed for
2038c2ecf20Sopenharmony_ci * colormap handling.
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_cienum cardtype { IS_VGA, IS_MV300 };
2068c2ecf20Sopenharmony_cistatic enum cardtype external_card_type = IS_VGA;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci/*
2098c2ecf20Sopenharmony_ci * The MV300 mixes the color registers. So we need an array of munged
2108c2ecf20Sopenharmony_ci * indices in order to access the correct reg.
2118c2ecf20Sopenharmony_ci */
2128c2ecf20Sopenharmony_cistatic int MV300_reg_1bit[2] = {
2138c2ecf20Sopenharmony_ci	0, 1
2148c2ecf20Sopenharmony_ci};
2158c2ecf20Sopenharmony_cistatic int MV300_reg_4bit[16] = {
2168c2ecf20Sopenharmony_ci	0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
2178c2ecf20Sopenharmony_ci};
2188c2ecf20Sopenharmony_cistatic int MV300_reg_8bit[256] = {
2198c2ecf20Sopenharmony_ci	0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
2208c2ecf20Sopenharmony_ci	8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
2218c2ecf20Sopenharmony_ci	4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
2228c2ecf20Sopenharmony_ci	12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
2238c2ecf20Sopenharmony_ci	2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
2248c2ecf20Sopenharmony_ci	10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
2258c2ecf20Sopenharmony_ci	6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
2268c2ecf20Sopenharmony_ci	14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
2278c2ecf20Sopenharmony_ci	1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
2288c2ecf20Sopenharmony_ci	9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
2298c2ecf20Sopenharmony_ci	5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
2308c2ecf20Sopenharmony_ci	13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
2318c2ecf20Sopenharmony_ci	3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
2328c2ecf20Sopenharmony_ci	11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
2338c2ecf20Sopenharmony_ci	7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
2348c2ecf20Sopenharmony_ci	15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int *MV300_reg = MV300_reg_8bit;
2388c2ecf20Sopenharmony_ci#endif /* ATAFB_EXT */
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int inverse;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ciextern int fontheight_8x8;
2448c2ecf20Sopenharmony_ciextern int fontwidth_8x8;
2458c2ecf20Sopenharmony_ciextern unsigned char fontdata_8x8[];
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ciextern int fontheight_8x16;
2488c2ecf20Sopenharmony_ciextern int fontwidth_8x16;
2498c2ecf20Sopenharmony_ciextern unsigned char fontdata_8x16[];
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/*
2528c2ecf20Sopenharmony_ci * struct fb_ops {
2538c2ecf20Sopenharmony_ci *	* open/release and usage marking
2548c2ecf20Sopenharmony_ci *	struct module *owner;
2558c2ecf20Sopenharmony_ci *	int (*fb_open)(struct fb_info *info, int user);
2568c2ecf20Sopenharmony_ci *	int (*fb_release)(struct fb_info *info, int user);
2578c2ecf20Sopenharmony_ci *
2588c2ecf20Sopenharmony_ci *	* For framebuffers with strange non linear layouts or that do not
2598c2ecf20Sopenharmony_ci *	* work with normal memory mapped access
2608c2ecf20Sopenharmony_ci *	ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
2618c2ecf20Sopenharmony_ci *	ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci *	* checks var and eventually tweaks it to something supported,
2648c2ecf20Sopenharmony_ci *	* DOES NOT MODIFY PAR *
2658c2ecf20Sopenharmony_ci *	int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
2668c2ecf20Sopenharmony_ci *
2678c2ecf20Sopenharmony_ci *	* set the video mode according to info->var *
2688c2ecf20Sopenharmony_ci *	int (*fb_set_par)(struct fb_info *info);
2698c2ecf20Sopenharmony_ci *
2708c2ecf20Sopenharmony_ci *	* set color register *
2718c2ecf20Sopenharmony_ci *	int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green,
2728c2ecf20Sopenharmony_ci *			    unsigned int blue, unsigned int transp, struct fb_info *info);
2738c2ecf20Sopenharmony_ci *
2748c2ecf20Sopenharmony_ci *	* set color registers in batch *
2758c2ecf20Sopenharmony_ci *	int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
2768c2ecf20Sopenharmony_ci *
2778c2ecf20Sopenharmony_ci *	* blank display *
2788c2ecf20Sopenharmony_ci *	int (*fb_blank)(int blank, struct fb_info *info);
2798c2ecf20Sopenharmony_ci *
2808c2ecf20Sopenharmony_ci *	* pan display *
2818c2ecf20Sopenharmony_ci *	int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci *	*** The meat of the drawing engine ***
2848c2ecf20Sopenharmony_ci *	* Draws a rectangle *
2858c2ecf20Sopenharmony_ci *	void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
2868c2ecf20Sopenharmony_ci *	* Copy data from area to another *
2878c2ecf20Sopenharmony_ci *	void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
2888c2ecf20Sopenharmony_ci *	* Draws a image to the display *
2898c2ecf20Sopenharmony_ci *	void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
2908c2ecf20Sopenharmony_ci *
2918c2ecf20Sopenharmony_ci *	* Draws cursor *
2928c2ecf20Sopenharmony_ci *	int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
2938c2ecf20Sopenharmony_ci *
2948c2ecf20Sopenharmony_ci *	* wait for blit idle, optional *
2958c2ecf20Sopenharmony_ci *	int (*fb_sync)(struct fb_info *info);
2968c2ecf20Sopenharmony_ci *
2978c2ecf20Sopenharmony_ci *	* perform fb specific ioctl (optional) *
2988c2ecf20Sopenharmony_ci *	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
2998c2ecf20Sopenharmony_ci *			unsigned long arg);
3008c2ecf20Sopenharmony_ci *
3018c2ecf20Sopenharmony_ci *	* Handle 32bit compat ioctl (optional) *
3028c2ecf20Sopenharmony_ci *	int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
3038c2ecf20Sopenharmony_ci *			unsigned long arg);
3048c2ecf20Sopenharmony_ci *
3058c2ecf20Sopenharmony_ci *	* perform fb specific mmap *
3068c2ecf20Sopenharmony_ci *	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
3078c2ecf20Sopenharmony_ci * } ;
3088c2ecf20Sopenharmony_ci */
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/* ++roman: This structure abstracts from the underlying hardware (ST(e),
3128c2ecf20Sopenharmony_ci * TT, or Falcon.
3138c2ecf20Sopenharmony_ci *
3148c2ecf20Sopenharmony_ci * int (*detect)(void)
3158c2ecf20Sopenharmony_ci *   This function should detect the current video mode settings and
3168c2ecf20Sopenharmony_ci *   store them in atafb_predefined[0] for later reference by the
3178c2ecf20Sopenharmony_ci *   user. Return the index+1 of an equivalent predefined mode or 0
3188c2ecf20Sopenharmony_ci *   if there is no such.
3198c2ecf20Sopenharmony_ci *
3208c2ecf20Sopenharmony_ci * int (*encode_fix)(struct fb_fix_screeninfo *fix,
3218c2ecf20Sopenharmony_ci *                   struct atafb_par *par)
3228c2ecf20Sopenharmony_ci *   This function should fill in the 'fix' structure based on the
3238c2ecf20Sopenharmony_ci *   values in the 'par' structure.
3248c2ecf20Sopenharmony_ci * !!! Obsolete, perhaps !!!
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci * int (*decode_var)(struct fb_var_screeninfo *var,
3278c2ecf20Sopenharmony_ci *                   struct atafb_par *par)
3288c2ecf20Sopenharmony_ci *   Get the video params out of 'var'. If a value doesn't fit, round
3298c2ecf20Sopenharmony_ci *   it up, if it's too big, return EINVAL.
3308c2ecf20Sopenharmony_ci *   Round up in the following order: bits_per_pixel, xres, yres,
3318c2ecf20Sopenharmony_ci *   xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
3328c2ecf20Sopenharmony_ci *   horizontal timing, vertical timing.
3338c2ecf20Sopenharmony_ci *
3348c2ecf20Sopenharmony_ci * int (*encode_var)(struct fb_var_screeninfo *var,
3358c2ecf20Sopenharmony_ci *                   struct atafb_par *par);
3368c2ecf20Sopenharmony_ci *   Fill the 'var' structure based on the values in 'par' and maybe
3378c2ecf20Sopenharmony_ci *   other values read out of the hardware.
3388c2ecf20Sopenharmony_ci *
3398c2ecf20Sopenharmony_ci * void (*get_par)(struct atafb_par *par)
3408c2ecf20Sopenharmony_ci *   Fill the hardware's 'par' structure.
3418c2ecf20Sopenharmony_ci *   !!! Used only by detect() !!!
3428c2ecf20Sopenharmony_ci *
3438c2ecf20Sopenharmony_ci * void (*set_par)(struct atafb_par *par)
3448c2ecf20Sopenharmony_ci *   Set the hardware according to 'par'.
3458c2ecf20Sopenharmony_ci *
3468c2ecf20Sopenharmony_ci * void (*set_screen_base)(void *s_base)
3478c2ecf20Sopenharmony_ci *   Set the base address of the displayed frame buffer. Only called
3488c2ecf20Sopenharmony_ci *   if yres_virtual > yres or xres_virtual > xres.
3498c2ecf20Sopenharmony_ci *
3508c2ecf20Sopenharmony_ci * int (*blank)(int blank_mode)
3518c2ecf20Sopenharmony_ci *   Blank the screen if blank_mode != 0, else unblank. If blank == NULL then
3528c2ecf20Sopenharmony_ci *   the caller blanks by setting the CLUT to all black. Return 0 if blanking
3538c2ecf20Sopenharmony_ci *   succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
3548c2ecf20Sopenharmony_ci *   doesn't support it. Implements VESA suspend and powerdown modes on
3558c2ecf20Sopenharmony_ci *   hardware that supports disabling hsync/vsync:
3568c2ecf20Sopenharmony_ci *       blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown.
3578c2ecf20Sopenharmony_ci */
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic struct fb_hwswitch {
3608c2ecf20Sopenharmony_ci	int (*detect)(void);
3618c2ecf20Sopenharmony_ci	int (*encode_fix)(struct fb_fix_screeninfo *fix,
3628c2ecf20Sopenharmony_ci			  struct atafb_par *par);
3638c2ecf20Sopenharmony_ci	int (*decode_var)(struct fb_var_screeninfo *var,
3648c2ecf20Sopenharmony_ci			  struct atafb_par *par);
3658c2ecf20Sopenharmony_ci	int (*encode_var)(struct fb_var_screeninfo *var,
3668c2ecf20Sopenharmony_ci			  struct atafb_par *par);
3678c2ecf20Sopenharmony_ci	void (*get_par)(struct atafb_par *par);
3688c2ecf20Sopenharmony_ci	void (*set_par)(struct atafb_par *par);
3698c2ecf20Sopenharmony_ci	void (*set_screen_base)(void *s_base);
3708c2ecf20Sopenharmony_ci	int (*blank)(int blank_mode);
3718c2ecf20Sopenharmony_ci	int (*pan_display)(struct fb_var_screeninfo *var,
3728c2ecf20Sopenharmony_ci			   struct fb_info *info);
3738c2ecf20Sopenharmony_ci} *fbhw;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic char *autodetect_names[] = { "autodetect", NULL };
3768c2ecf20Sopenharmony_cistatic char *stlow_names[] = { "stlow", NULL };
3778c2ecf20Sopenharmony_cistatic char *stmid_names[] = { "stmid", "default5", NULL };
3788c2ecf20Sopenharmony_cistatic char *sthigh_names[] = { "sthigh", "default4", NULL };
3798c2ecf20Sopenharmony_cistatic char *ttlow_names[] = { "ttlow", NULL };
3808c2ecf20Sopenharmony_cistatic char *ttmid_names[] = { "ttmid", "default1", NULL };
3818c2ecf20Sopenharmony_cistatic char *tthigh_names[] = { "tthigh", "default2", NULL };
3828c2ecf20Sopenharmony_cistatic char *vga2_names[] = { "vga2", NULL };
3838c2ecf20Sopenharmony_cistatic char *vga4_names[] = { "vga4", NULL };
3848c2ecf20Sopenharmony_cistatic char *vga16_names[] = { "vga16", "default3", NULL };
3858c2ecf20Sopenharmony_cistatic char *vga256_names[] = { "vga256", NULL };
3868c2ecf20Sopenharmony_cistatic char *falh2_names[] = { "falh2", NULL };
3878c2ecf20Sopenharmony_cistatic char *falh16_names[] = { "falh16", NULL };
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic char **fb_var_names[] = {
3908c2ecf20Sopenharmony_ci	autodetect_names,
3918c2ecf20Sopenharmony_ci	stlow_names,
3928c2ecf20Sopenharmony_ci	stmid_names,
3938c2ecf20Sopenharmony_ci	sthigh_names,
3948c2ecf20Sopenharmony_ci	ttlow_names,
3958c2ecf20Sopenharmony_ci	ttmid_names,
3968c2ecf20Sopenharmony_ci	tthigh_names,
3978c2ecf20Sopenharmony_ci	vga2_names,
3988c2ecf20Sopenharmony_ci	vga4_names,
3998c2ecf20Sopenharmony_ci	vga16_names,
4008c2ecf20Sopenharmony_ci	vga256_names,
4018c2ecf20Sopenharmony_ci	falh2_names,
4028c2ecf20Sopenharmony_ci	falh16_names,
4038c2ecf20Sopenharmony_ci	NULL
4048c2ecf20Sopenharmony_ci};
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo atafb_predefined[] = {
4078c2ecf20Sopenharmony_ci	/*
4088c2ecf20Sopenharmony_ci	 * yres_virtual == 0 means use hw-scrolling if possible, else yres
4098c2ecf20Sopenharmony_ci	 */
4108c2ecf20Sopenharmony_ci	{ /* autodetect */
4118c2ecf20Sopenharmony_ci	  0, 0, 0, 0, 0, 0, 0, 0,		/* xres-grayscale */
4128c2ecf20Sopenharmony_ci	  {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},	/* red green blue tran*/
4138c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4148c2ecf20Sopenharmony_ci	{ /* st low */
4158c2ecf20Sopenharmony_ci	  320, 200, 320, 0, 0, 0, 4, 0,
4168c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4178c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4188c2ecf20Sopenharmony_ci	{ /* st mid */
4198c2ecf20Sopenharmony_ci	  640, 200, 640, 0, 0, 0, 2, 0,
4208c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4218c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4228c2ecf20Sopenharmony_ci	{ /* st high */
4238c2ecf20Sopenharmony_ci	  640, 400, 640, 0, 0, 0, 1, 0,
4248c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4258c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4268c2ecf20Sopenharmony_ci	{ /* tt low */
4278c2ecf20Sopenharmony_ci	  320, 480, 320, 0, 0, 0, 8, 0,
4288c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4298c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4308c2ecf20Sopenharmony_ci	{ /* tt mid */
4318c2ecf20Sopenharmony_ci	  640, 480, 640, 0, 0, 0, 4, 0,
4328c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4338c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4348c2ecf20Sopenharmony_ci	{ /* tt high */
4358c2ecf20Sopenharmony_ci	  1280, 960, 1280, 0, 0, 0, 1, 0,
4368c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4378c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4388c2ecf20Sopenharmony_ci	{ /* vga2 */
4398c2ecf20Sopenharmony_ci	  640, 480, 640, 0, 0, 0, 1, 0,
4408c2ecf20Sopenharmony_ci	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
4418c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4428c2ecf20Sopenharmony_ci	{ /* vga4 */
4438c2ecf20Sopenharmony_ci	  640, 480, 640, 0, 0, 0, 2, 0,
4448c2ecf20Sopenharmony_ci	  {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
4458c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4468c2ecf20Sopenharmony_ci	{ /* vga16 */
4478c2ecf20Sopenharmony_ci	  640, 480, 640, 0, 0, 0, 4, 0,
4488c2ecf20Sopenharmony_ci	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
4498c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4508c2ecf20Sopenharmony_ci	{ /* vga256 */
4518c2ecf20Sopenharmony_ci	  640, 480, 640, 0, 0, 0, 8, 0,
4528c2ecf20Sopenharmony_ci	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
4538c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4548c2ecf20Sopenharmony_ci	{ /* falh2 */
4558c2ecf20Sopenharmony_ci	  896, 608, 896, 0, 0, 0, 1, 0,
4568c2ecf20Sopenharmony_ci	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
4578c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4588c2ecf20Sopenharmony_ci	{ /* falh16 */
4598c2ecf20Sopenharmony_ci	  896, 608, 896, 0, 0, 0, 4, 0,
4608c2ecf20Sopenharmony_ci	  {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
4618c2ecf20Sopenharmony_ci	  0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
4628c2ecf20Sopenharmony_ci};
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int num_atafb_predefined = ARRAY_SIZE(atafb_predefined);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic struct fb_videomode atafb_modedb[] __initdata = {
4678c2ecf20Sopenharmony_ci	/*
4688c2ecf20Sopenharmony_ci	 *  Atari Video Modes
4698c2ecf20Sopenharmony_ci	 *
4708c2ecf20Sopenharmony_ci	 *  If you change these, make sure to update DEFMODE_* as well!
4718c2ecf20Sopenharmony_ci	 */
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/*
4748c2ecf20Sopenharmony_ci	 *  ST/TT Video Modes
4758c2ecf20Sopenharmony_ci	 */
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	{
4788c2ecf20Sopenharmony_ci		/* 320x200, 15 kHz, 60 Hz (ST low) */
4798c2ecf20Sopenharmony_ci		"st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4,
4808c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
4818c2ecf20Sopenharmony_ci	}, {
4828c2ecf20Sopenharmony_ci		/* 640x200, 15 kHz, 60 Hz (ST medium) */
4838c2ecf20Sopenharmony_ci		"st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4,
4848c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
4858c2ecf20Sopenharmony_ci	}, {
4868c2ecf20Sopenharmony_ci		/* 640x400, 30.25 kHz, 63.5 Hz (ST high) */
4878c2ecf20Sopenharmony_ci		"st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4,
4888c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
4898c2ecf20Sopenharmony_ci	}, {
4908c2ecf20Sopenharmony_ci		/* 320x480, 15 kHz, 60 Hz (TT low) */
4918c2ecf20Sopenharmony_ci		"tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30,
4928c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
4938c2ecf20Sopenharmony_ci	}, {
4948c2ecf20Sopenharmony_ci		/* 640x480, 29 kHz, 57 Hz (TT medium) */
4958c2ecf20Sopenharmony_ci		"tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30,
4968c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
4978c2ecf20Sopenharmony_ci	}, {
4988c2ecf20Sopenharmony_ci		/* 1280x960, 29 kHz, 60 Hz (TT high) */
4998c2ecf20Sopenharmony_ci		"tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30,
5008c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
5018c2ecf20Sopenharmony_ci	},
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/*
5048c2ecf20Sopenharmony_ci	 *  VGA Video Modes
5058c2ecf20Sopenharmony_ci	 */
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	{
5088c2ecf20Sopenharmony_ci		/* 640x480, 31 kHz, 60 Hz (VGA) */
5098c2ecf20Sopenharmony_ci		"vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3,
5108c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
5118c2ecf20Sopenharmony_ci	}, {
5128c2ecf20Sopenharmony_ci		/* 640x400, 31 kHz, 70 Hz (VGA) */
5138c2ecf20Sopenharmony_ci		"vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3,
5148c2ecf20Sopenharmony_ci		FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
5158c2ecf20Sopenharmony_ci	},
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/*
5188c2ecf20Sopenharmony_ci	 *  Falcon HiRes Video Modes
5198c2ecf20Sopenharmony_ci	 */
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	{
5228c2ecf20Sopenharmony_ci		/* 896x608, 31 kHz, 60 Hz (Falcon High) */
5238c2ecf20Sopenharmony_ci		"falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3,
5248c2ecf20Sopenharmony_ci		0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
5258c2ecf20Sopenharmony_ci	},
5268c2ecf20Sopenharmony_ci};
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci#define NUM_TOTAL_MODES  ARRAY_SIZE(atafb_modedb)
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic char *mode_option __initdata = NULL;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci /* default modes */
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci#define DEFMODE_TT	5		/* "tt-high" for TT */
5358c2ecf20Sopenharmony_ci#define DEFMODE_F30	7		/* "vga70" for Falcon */
5368c2ecf20Sopenharmony_ci#define DEFMODE_STE	2		/* "st-high" for ST/E */
5378c2ecf20Sopenharmony_ci#define DEFMODE_EXT	6		/* "vga" for external */
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic int get_video_mode(char *vname)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	char ***name_list;
5438c2ecf20Sopenharmony_ci	char **name;
5448c2ecf20Sopenharmony_ci	int i;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	name_list = fb_var_names;
5478c2ecf20Sopenharmony_ci	for (i = 0; i < num_atafb_predefined; i++) {
5488c2ecf20Sopenharmony_ci		name = *name_list++;
5498c2ecf20Sopenharmony_ci		if (!name || !*name)
5508c2ecf20Sopenharmony_ci			break;
5518c2ecf20Sopenharmony_ci		while (*name) {
5528c2ecf20Sopenharmony_ci			if (!strcmp(vname, *name))
5538c2ecf20Sopenharmony_ci				return i + 1;
5548c2ecf20Sopenharmony_ci			name++;
5558c2ecf20Sopenharmony_ci		}
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci	return 0;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci/* ------------------- TT specific functions ---------------------- */
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci#ifdef ATAFB_TT
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	int mode;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	strcpy(fix->id, "Atari Builtin");
5718c2ecf20Sopenharmony_ci	fix->smem_start = phys_screen_base;
5728c2ecf20Sopenharmony_ci	fix->smem_len = screen_len;
5738c2ecf20Sopenharmony_ci	fix->type = FB_TYPE_INTERLEAVED_PLANES;
5748c2ecf20Sopenharmony_ci	fix->type_aux = 2;
5758c2ecf20Sopenharmony_ci	fix->visual = FB_VISUAL_PSEUDOCOLOR;
5768c2ecf20Sopenharmony_ci	mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
5778c2ecf20Sopenharmony_ci	if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
5788c2ecf20Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
5798c2ecf20Sopenharmony_ci		fix->type_aux = 0;
5808c2ecf20Sopenharmony_ci		if (mode == TT_SHIFTER_TTHIGH)
5818c2ecf20Sopenharmony_ci			fix->visual = FB_VISUAL_MONO01;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci	fix->xpanstep = 0;
5848c2ecf20Sopenharmony_ci	fix->ypanstep = 1;
5858c2ecf20Sopenharmony_ci	fix->ywrapstep = 0;
5868c2ecf20Sopenharmony_ci	fix->line_length = par->next_line;
5878c2ecf20Sopenharmony_ci	fix->accel = FB_ACCEL_ATARIBLITT;
5888c2ecf20Sopenharmony_ci	return 0;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	int xres = var->xres;
5948c2ecf20Sopenharmony_ci	int yres = var->yres;
5958c2ecf20Sopenharmony_ci	int bpp = var->bits_per_pixel;
5968c2ecf20Sopenharmony_ci	int linelen;
5978c2ecf20Sopenharmony_ci	int yres_virtual = var->yres_virtual;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (mono_moni) {
6008c2ecf20Sopenharmony_ci		if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2)
6018c2ecf20Sopenharmony_ci			return -EINVAL;
6028c2ecf20Sopenharmony_ci		par->hw.tt.mode = TT_SHIFTER_TTHIGH;
6038c2ecf20Sopenharmony_ci		xres = sttt_xres * 2;
6048c2ecf20Sopenharmony_ci		yres = tt_yres * 2;
6058c2ecf20Sopenharmony_ci		bpp = 1;
6068c2ecf20Sopenharmony_ci	} else {
6078c2ecf20Sopenharmony_ci		if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
6088c2ecf20Sopenharmony_ci			return -EINVAL;
6098c2ecf20Sopenharmony_ci		if (bpp > 4) {
6108c2ecf20Sopenharmony_ci			if (xres > sttt_xres / 2 || yres > tt_yres)
6118c2ecf20Sopenharmony_ci				return -EINVAL;
6128c2ecf20Sopenharmony_ci			par->hw.tt.mode = TT_SHIFTER_TTLOW;
6138c2ecf20Sopenharmony_ci			xres = sttt_xres / 2;
6148c2ecf20Sopenharmony_ci			yres = tt_yres;
6158c2ecf20Sopenharmony_ci			bpp = 8;
6168c2ecf20Sopenharmony_ci		} else if (bpp > 2) {
6178c2ecf20Sopenharmony_ci			if (xres > sttt_xres || yres > tt_yres)
6188c2ecf20Sopenharmony_ci				return -EINVAL;
6198c2ecf20Sopenharmony_ci			if (xres > sttt_xres / 2 || yres > st_yres / 2) {
6208c2ecf20Sopenharmony_ci				par->hw.tt.mode = TT_SHIFTER_TTMID;
6218c2ecf20Sopenharmony_ci				xres = sttt_xres;
6228c2ecf20Sopenharmony_ci				yres = tt_yres;
6238c2ecf20Sopenharmony_ci				bpp = 4;
6248c2ecf20Sopenharmony_ci			} else {
6258c2ecf20Sopenharmony_ci				par->hw.tt.mode = TT_SHIFTER_STLOW;
6268c2ecf20Sopenharmony_ci				xres = sttt_xres / 2;
6278c2ecf20Sopenharmony_ci				yres = st_yres / 2;
6288c2ecf20Sopenharmony_ci				bpp = 4;
6298c2ecf20Sopenharmony_ci			}
6308c2ecf20Sopenharmony_ci		} else if (bpp > 1) {
6318c2ecf20Sopenharmony_ci			if (xres > sttt_xres || yres > st_yres / 2)
6328c2ecf20Sopenharmony_ci				return -EINVAL;
6338c2ecf20Sopenharmony_ci			par->hw.tt.mode = TT_SHIFTER_STMID;
6348c2ecf20Sopenharmony_ci			xres = sttt_xres;
6358c2ecf20Sopenharmony_ci			yres = st_yres / 2;
6368c2ecf20Sopenharmony_ci			bpp = 2;
6378c2ecf20Sopenharmony_ci		} else if (var->xres > sttt_xres || var->yres > st_yres) {
6388c2ecf20Sopenharmony_ci			return -EINVAL;
6398c2ecf20Sopenharmony_ci		} else {
6408c2ecf20Sopenharmony_ci			par->hw.tt.mode = TT_SHIFTER_STHIGH;
6418c2ecf20Sopenharmony_ci			xres = sttt_xres;
6428c2ecf20Sopenharmony_ci			yres = st_yres;
6438c2ecf20Sopenharmony_ci			bpp = 1;
6448c2ecf20Sopenharmony_ci		}
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci	if (yres_virtual <= 0)
6478c2ecf20Sopenharmony_ci		yres_virtual = 0;
6488c2ecf20Sopenharmony_ci	else if (yres_virtual < yres)
6498c2ecf20Sopenharmony_ci		yres_virtual = yres;
6508c2ecf20Sopenharmony_ci	if (var->sync & FB_SYNC_EXT)
6518c2ecf20Sopenharmony_ci		par->hw.tt.sync = 0;
6528c2ecf20Sopenharmony_ci	else
6538c2ecf20Sopenharmony_ci		par->hw.tt.sync = 1;
6548c2ecf20Sopenharmony_ci	linelen = xres * bpp / 8;
6558c2ecf20Sopenharmony_ci	if (yres_virtual * linelen > screen_len && screen_len)
6568c2ecf20Sopenharmony_ci		return -EINVAL;
6578c2ecf20Sopenharmony_ci	if (yres * linelen > screen_len && screen_len)
6588c2ecf20Sopenharmony_ci		return -EINVAL;
6598c2ecf20Sopenharmony_ci	if (var->yoffset + yres > yres_virtual && yres_virtual)
6608c2ecf20Sopenharmony_ci		return -EINVAL;
6618c2ecf20Sopenharmony_ci	par->yres_virtual = yres_virtual;
6628c2ecf20Sopenharmony_ci	par->screen_base = screen_base + var->yoffset * linelen;
6638c2ecf20Sopenharmony_ci	par->next_line = linelen;
6648c2ecf20Sopenharmony_ci	return 0;
6658c2ecf20Sopenharmony_ci}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	int linelen;
6708c2ecf20Sopenharmony_ci	memset(var, 0, sizeof(struct fb_var_screeninfo));
6718c2ecf20Sopenharmony_ci	var->red.offset = 0;
6728c2ecf20Sopenharmony_ci	var->red.length = 4;
6738c2ecf20Sopenharmony_ci	var->red.msb_right = 0;
6748c2ecf20Sopenharmony_ci	var->grayscale = 0;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	var->pixclock = 31041;
6778c2ecf20Sopenharmony_ci	var->left_margin = 120;		/* these may be incorrect */
6788c2ecf20Sopenharmony_ci	var->right_margin = 100;
6798c2ecf20Sopenharmony_ci	var->upper_margin = 8;
6808c2ecf20Sopenharmony_ci	var->lower_margin = 16;
6818c2ecf20Sopenharmony_ci	var->hsync_len = 140;
6828c2ecf20Sopenharmony_ci	var->vsync_len = 30;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	var->height = -1;
6858c2ecf20Sopenharmony_ci	var->width = -1;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (par->hw.tt.sync & 1)
6888c2ecf20Sopenharmony_ci		var->sync = 0;
6898c2ecf20Sopenharmony_ci	else
6908c2ecf20Sopenharmony_ci		var->sync = FB_SYNC_EXT;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
6938c2ecf20Sopenharmony_ci	case TT_SHIFTER_STLOW:
6948c2ecf20Sopenharmony_ci		var->xres = sttt_xres / 2;
6958c2ecf20Sopenharmony_ci		var->xres_virtual = sttt_xres_virtual / 2;
6968c2ecf20Sopenharmony_ci		var->yres = st_yres / 2;
6978c2ecf20Sopenharmony_ci		var->bits_per_pixel = 4;
6988c2ecf20Sopenharmony_ci		break;
6998c2ecf20Sopenharmony_ci	case TT_SHIFTER_STMID:
7008c2ecf20Sopenharmony_ci		var->xres = sttt_xres;
7018c2ecf20Sopenharmony_ci		var->xres_virtual = sttt_xres_virtual;
7028c2ecf20Sopenharmony_ci		var->yres = st_yres / 2;
7038c2ecf20Sopenharmony_ci		var->bits_per_pixel = 2;
7048c2ecf20Sopenharmony_ci		break;
7058c2ecf20Sopenharmony_ci	case TT_SHIFTER_STHIGH:
7068c2ecf20Sopenharmony_ci		var->xres = sttt_xres;
7078c2ecf20Sopenharmony_ci		var->xres_virtual = sttt_xres_virtual;
7088c2ecf20Sopenharmony_ci		var->yres = st_yres;
7098c2ecf20Sopenharmony_ci		var->bits_per_pixel = 1;
7108c2ecf20Sopenharmony_ci		break;
7118c2ecf20Sopenharmony_ci	case TT_SHIFTER_TTLOW:
7128c2ecf20Sopenharmony_ci		var->xres = sttt_xres / 2;
7138c2ecf20Sopenharmony_ci		var->xres_virtual = sttt_xres_virtual / 2;
7148c2ecf20Sopenharmony_ci		var->yres = tt_yres;
7158c2ecf20Sopenharmony_ci		var->bits_per_pixel = 8;
7168c2ecf20Sopenharmony_ci		break;
7178c2ecf20Sopenharmony_ci	case TT_SHIFTER_TTMID:
7188c2ecf20Sopenharmony_ci		var->xres = sttt_xres;
7198c2ecf20Sopenharmony_ci		var->xres_virtual = sttt_xres_virtual;
7208c2ecf20Sopenharmony_ci		var->yres = tt_yres;
7218c2ecf20Sopenharmony_ci		var->bits_per_pixel = 4;
7228c2ecf20Sopenharmony_ci		break;
7238c2ecf20Sopenharmony_ci	case TT_SHIFTER_TTHIGH:
7248c2ecf20Sopenharmony_ci		var->red.length = 0;
7258c2ecf20Sopenharmony_ci		var->xres = sttt_xres * 2;
7268c2ecf20Sopenharmony_ci		var->xres_virtual = sttt_xres_virtual * 2;
7278c2ecf20Sopenharmony_ci		var->yres = tt_yres * 2;
7288c2ecf20Sopenharmony_ci		var->bits_per_pixel = 1;
7298c2ecf20Sopenharmony_ci		break;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci	var->blue = var->green = var->red;
7328c2ecf20Sopenharmony_ci	var->transp.offset = 0;
7338c2ecf20Sopenharmony_ci	var->transp.length = 0;
7348c2ecf20Sopenharmony_ci	var->transp.msb_right = 0;
7358c2ecf20Sopenharmony_ci	linelen = var->xres_virtual * var->bits_per_pixel / 8;
7368c2ecf20Sopenharmony_ci	if (!use_hwscroll)
7378c2ecf20Sopenharmony_ci		var->yres_virtual = var->yres;
7388c2ecf20Sopenharmony_ci	else if (screen_len) {
7398c2ecf20Sopenharmony_ci		if (par->yres_virtual)
7408c2ecf20Sopenharmony_ci			var->yres_virtual = par->yres_virtual;
7418c2ecf20Sopenharmony_ci		else
7428c2ecf20Sopenharmony_ci			/* yres_virtual == 0 means use maximum */
7438c2ecf20Sopenharmony_ci			var->yres_virtual = screen_len / linelen;
7448c2ecf20Sopenharmony_ci	} else {
7458c2ecf20Sopenharmony_ci		if (hwscroll < 0)
7468c2ecf20Sopenharmony_ci			var->yres_virtual = 2 * var->yres;
7478c2ecf20Sopenharmony_ci		else
7488c2ecf20Sopenharmony_ci			var->yres_virtual = var->yres + hwscroll * 16;
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci	var->xoffset = 0;
7518c2ecf20Sopenharmony_ci	if (screen_base)
7528c2ecf20Sopenharmony_ci		var->yoffset = (par->screen_base - screen_base) / linelen;
7538c2ecf20Sopenharmony_ci	else
7548c2ecf20Sopenharmony_ci		var->yoffset = 0;
7558c2ecf20Sopenharmony_ci	var->nonstd = 0;
7568c2ecf20Sopenharmony_ci	var->activate = 0;
7578c2ecf20Sopenharmony_ci	var->vmode = FB_VMODE_NONINTERLACED;
7588c2ecf20Sopenharmony_ci	return 0;
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic void tt_get_par(struct atafb_par *par)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	unsigned long addr;
7648c2ecf20Sopenharmony_ci	par->hw.tt.mode = shifter_tt.tt_shiftmode;
7658c2ecf20Sopenharmony_ci	par->hw.tt.sync = shifter_st.syncmode;
7668c2ecf20Sopenharmony_ci	addr = ((shifter_st.bas_hi & 0xff) << 16) |
7678c2ecf20Sopenharmony_ci	       ((shifter_st.bas_md & 0xff) << 8)  |
7688c2ecf20Sopenharmony_ci	       ((shifter_st.bas_lo & 0xff));
7698c2ecf20Sopenharmony_ci	par->screen_base = atari_stram_to_virt(addr);
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic void tt_set_par(struct atafb_par *par)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	shifter_tt.tt_shiftmode = par->hw.tt.mode;
7758c2ecf20Sopenharmony_ci	shifter_st.syncmode = par->hw.tt.sync;
7768c2ecf20Sopenharmony_ci	/* only set screen_base if really necessary */
7778c2ecf20Sopenharmony_ci	if (current_par.screen_base != par->screen_base)
7788c2ecf20Sopenharmony_ci		fbhw->set_screen_base(par->screen_base);
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic int tt_setcolreg(unsigned int regno, unsigned int red,
7828c2ecf20Sopenharmony_ci			unsigned int green, unsigned int blue,
7838c2ecf20Sopenharmony_ci			unsigned int transp, struct fb_info *info)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
7868c2ecf20Sopenharmony_ci		regno += 254;
7878c2ecf20Sopenharmony_ci	if (regno > 255)
7888c2ecf20Sopenharmony_ci		return 1;
7898c2ecf20Sopenharmony_ci	tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
7908c2ecf20Sopenharmony_ci			     (blue >> 12));
7918c2ecf20Sopenharmony_ci	if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
7928c2ecf20Sopenharmony_ci	    TT_SHIFTER_STHIGH && regno == 254)
7938c2ecf20Sopenharmony_ci		tt_palette[0] = 0;
7948c2ecf20Sopenharmony_ci	return 0;
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic int tt_detect(void)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	struct atafb_par par;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	/* Determine the connected monitor: The DMA sound must be
8028c2ecf20Sopenharmony_ci	 * disabled before reading the MFP GPIP, because the Sound
8038c2ecf20Sopenharmony_ci	 * Done Signal and the Monochrome Detect are XORed together!
8048c2ecf20Sopenharmony_ci	 *
8058c2ecf20Sopenharmony_ci	 * Even on a TT, we should look if there is a DMA sound. It was
8068c2ecf20Sopenharmony_ci	 * announced that the Eagle is TT compatible, but only the PCM is
8078c2ecf20Sopenharmony_ci	 * missing...
8088c2ecf20Sopenharmony_ci	 */
8098c2ecf20Sopenharmony_ci	if (ATARIHW_PRESENT(PCM_8BIT)) {
8108c2ecf20Sopenharmony_ci		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
8118c2ecf20Sopenharmony_ci		udelay(20);		/* wait a while for things to settle down */
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci	mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	tt_get_par(&par);
8168c2ecf20Sopenharmony_ci	tt_encode_var(&atafb_predefined[0], &par);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	return 1;
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci#endif /* ATAFB_TT */
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci/* ------------------- Falcon specific functions ---------------------- */
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_cistatic int mon_type;		/* Falcon connected monitor */
8288c2ecf20Sopenharmony_cistatic int f030_bus_width;	/* Falcon ram bus width (for vid_control) */
8298c2ecf20Sopenharmony_ci#define F_MON_SM	0
8308c2ecf20Sopenharmony_ci#define F_MON_SC	1
8318c2ecf20Sopenharmony_ci#define F_MON_VGA	2
8328c2ecf20Sopenharmony_ci#define F_MON_TV	3
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic struct pixel_clock {
8358c2ecf20Sopenharmony_ci	unsigned long f;	/* f/[Hz] */
8368c2ecf20Sopenharmony_ci	unsigned long t;	/* t/[ps] (=1/f) */
8378c2ecf20Sopenharmony_ci	int right, hsync, left;	/* standard timing in clock cycles, not pixel */
8388c2ecf20Sopenharmony_ci	/* hsync initialized in falcon_detect() */
8398c2ecf20Sopenharmony_ci	int sync_mask;		/* or-mask for hw.falcon.sync to set this clock */
8408c2ecf20Sopenharmony_ci	int control_mask;	/* ditto, for hw.falcon.vid_control */
8418c2ecf20Sopenharmony_ci} f25 = {
8428c2ecf20Sopenharmony_ci	25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25
8438c2ecf20Sopenharmony_ci}, f32 = {
8448c2ecf20Sopenharmony_ci	32000000, 31250, 18, 0, 42, 0x0, 0
8458c2ecf20Sopenharmony_ci}, fext = {
8468c2ecf20Sopenharmony_ci	0, 0, 18, 0, 42, 0x1, 0
8478c2ecf20Sopenharmony_ci};
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci/* VIDEL-prescale values [mon_type][pixel_length from VCO] */
8508c2ecf20Sopenharmony_cistatic int vdl_prescale[4][3] = {
8518c2ecf20Sopenharmony_ci	{ 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 }
8528c2ecf20Sopenharmony_ci};
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci/* Default hsync timing [mon_type] in picoseconds */
8558c2ecf20Sopenharmony_cistatic long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 };
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic inline int hxx_prescale(struct falcon_hw *hw)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	return hw->ste_mode ? 16
8608c2ecf20Sopenharmony_ci			    : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic int falcon_encode_fix(struct fb_fix_screeninfo *fix,
8648c2ecf20Sopenharmony_ci			     struct atafb_par *par)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	strcpy(fix->id, "Atari Builtin");
8678c2ecf20Sopenharmony_ci	fix->smem_start = phys_screen_base;
8688c2ecf20Sopenharmony_ci	fix->smem_len = screen_len;
8698c2ecf20Sopenharmony_ci	fix->type = FB_TYPE_INTERLEAVED_PLANES;
8708c2ecf20Sopenharmony_ci	fix->type_aux = 2;
8718c2ecf20Sopenharmony_ci	fix->visual = FB_VISUAL_PSEUDOCOLOR;
8728c2ecf20Sopenharmony_ci	fix->xpanstep = 1;
8738c2ecf20Sopenharmony_ci	fix->ypanstep = 1;
8748c2ecf20Sopenharmony_ci	fix->ywrapstep = 0;
8758c2ecf20Sopenharmony_ci	if (par->hw.falcon.mono) {
8768c2ecf20Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
8778c2ecf20Sopenharmony_ci		fix->type_aux = 0;
8788c2ecf20Sopenharmony_ci		/* no smooth scrolling with longword aligned video mem */
8798c2ecf20Sopenharmony_ci		fix->xpanstep = 32;
8808c2ecf20Sopenharmony_ci	} else if (par->hw.falcon.f_shift & 0x100) {
8818c2ecf20Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
8828c2ecf20Sopenharmony_ci		fix->type_aux = 0;
8838c2ecf20Sopenharmony_ci		/* Is this ok or should it be DIRECTCOLOR? */
8848c2ecf20Sopenharmony_ci		fix->visual = FB_VISUAL_TRUECOLOR;
8858c2ecf20Sopenharmony_ci		fix->xpanstep = 2;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci	fix->line_length = par->next_line;
8888c2ecf20Sopenharmony_ci	fix->accel = FB_ACCEL_ATARIBLITT;
8898c2ecf20Sopenharmony_ci	return 0;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic int falcon_decode_var(struct fb_var_screeninfo *var,
8938c2ecf20Sopenharmony_ci			     struct atafb_par *par)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	int bpp = var->bits_per_pixel;
8968c2ecf20Sopenharmony_ci	int xres = var->xres;
8978c2ecf20Sopenharmony_ci	int yres = var->yres;
8988c2ecf20Sopenharmony_ci	int xres_virtual = var->xres_virtual;
8998c2ecf20Sopenharmony_ci	int yres_virtual = var->yres_virtual;
9008c2ecf20Sopenharmony_ci	int left_margin, right_margin, hsync_len;
9018c2ecf20Sopenharmony_ci	int upper_margin, lower_margin, vsync_len;
9028c2ecf20Sopenharmony_ci	int linelen;
9038c2ecf20Sopenharmony_ci	int interlace = 0, doubleline = 0;
9048c2ecf20Sopenharmony_ci	struct pixel_clock *pclock;
9058c2ecf20Sopenharmony_ci	int plen;			/* width of pixel in clock cycles */
9068c2ecf20Sopenharmony_ci	int xstretch;
9078c2ecf20Sopenharmony_ci	int prescale;
9088c2ecf20Sopenharmony_ci	int longoffset = 0;
9098c2ecf20Sopenharmony_ci	int hfreq, vfreq;
9108c2ecf20Sopenharmony_ci	int hdb_off, hde_off, base_off;
9118c2ecf20Sopenharmony_ci	int gstart, gend1, gend2, align;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci/*
9148c2ecf20Sopenharmony_ci	Get the video params out of 'var'. If a value doesn't fit, round
9158c2ecf20Sopenharmony_ci	it up, if it's too big, return EINVAL.
9168c2ecf20Sopenharmony_ci	Round up in the following order: bits_per_pixel, xres, yres,
9178c2ecf20Sopenharmony_ci	xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
9188c2ecf20Sopenharmony_ci	horizontal timing, vertical timing.
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	There is a maximum of screen resolution determined by pixelclock
9218c2ecf20Sopenharmony_ci	and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
9228c2ecf20Sopenharmony_ci	In interlace mode this is     "     *    "     *vfmin <= pixelclock.
9238c2ecf20Sopenharmony_ci	Additional constraints: hfreq.
9248c2ecf20Sopenharmony_ci	Frequency range for multisync monitors is given via command line.
9258c2ecf20Sopenharmony_ci	For TV and SM124 both frequencies are fixed.
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0)
9288c2ecf20Sopenharmony_ci	Y % 16 == 0 to fit 8x16 font
9298c2ecf20Sopenharmony_ci	Y % 8 == 0 if Y<400
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	Currently interlace and doubleline mode in var are ignored.
9328c2ecf20Sopenharmony_ci	On SM124 and TV only the standard resolutions can be used.
9338c2ecf20Sopenharmony_ci*/
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	/* Reject uninitialized mode */
9368c2ecf20Sopenharmony_ci	if (!xres || !yres || !bpp)
9378c2ecf20Sopenharmony_ci		return -EINVAL;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	if (mon_type == F_MON_SM && bpp != 1)
9408c2ecf20Sopenharmony_ci		return -EINVAL;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (bpp <= 1) {
9438c2ecf20Sopenharmony_ci		bpp = 1;
9448c2ecf20Sopenharmony_ci		par->hw.falcon.f_shift = 0x400;
9458c2ecf20Sopenharmony_ci		par->hw.falcon.st_shift = 0x200;
9468c2ecf20Sopenharmony_ci	} else if (bpp <= 2) {
9478c2ecf20Sopenharmony_ci		bpp = 2;
9488c2ecf20Sopenharmony_ci		par->hw.falcon.f_shift = 0x000;
9498c2ecf20Sopenharmony_ci		par->hw.falcon.st_shift = 0x100;
9508c2ecf20Sopenharmony_ci	} else if (bpp <= 4) {
9518c2ecf20Sopenharmony_ci		bpp = 4;
9528c2ecf20Sopenharmony_ci		par->hw.falcon.f_shift = 0x000;
9538c2ecf20Sopenharmony_ci		par->hw.falcon.st_shift = 0x000;
9548c2ecf20Sopenharmony_ci	} else if (bpp <= 8) {
9558c2ecf20Sopenharmony_ci		bpp = 8;
9568c2ecf20Sopenharmony_ci		par->hw.falcon.f_shift = 0x010;
9578c2ecf20Sopenharmony_ci	} else if (bpp <= 16) {
9588c2ecf20Sopenharmony_ci		bpp = 16;		/* packed pixel mode */
9598c2ecf20Sopenharmony_ci		par->hw.falcon.f_shift = 0x100;	/* hicolor, no overlay */
9608c2ecf20Sopenharmony_ci	} else
9618c2ecf20Sopenharmony_ci		return -EINVAL;
9628c2ecf20Sopenharmony_ci	par->hw.falcon.bpp = bpp;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (mon_type == F_MON_SM || DontCalcRes) {
9658c2ecf20Sopenharmony_ci		/* Skip all calculations. VGA/TV/SC1224 only supported. */
9668c2ecf20Sopenharmony_ci		struct fb_var_screeninfo *myvar = &atafb_predefined[0];
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci		if (bpp > myvar->bits_per_pixel ||
9698c2ecf20Sopenharmony_ci		    var->xres > myvar->xres ||
9708c2ecf20Sopenharmony_ci		    var->yres > myvar->yres)
9718c2ecf20Sopenharmony_ci			return -EINVAL;
9728c2ecf20Sopenharmony_ci		fbhw->get_par(par);	/* Current par will be new par */
9738c2ecf20Sopenharmony_ci		goto set_screen_base;	/* Don't forget this */
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/* Only some fixed resolutions < 640x400 */
9778c2ecf20Sopenharmony_ci	if (xres <= 320)
9788c2ecf20Sopenharmony_ci		xres = 320;
9798c2ecf20Sopenharmony_ci	else if (xres <= 640 && bpp != 16)
9808c2ecf20Sopenharmony_ci		xres = 640;
9818c2ecf20Sopenharmony_ci	if (yres <= 200)
9828c2ecf20Sopenharmony_ci		yres = 200;
9838c2ecf20Sopenharmony_ci	else if (yres <= 240)
9848c2ecf20Sopenharmony_ci		yres = 240;
9858c2ecf20Sopenharmony_ci	else if (yres <= 400)
9868c2ecf20Sopenharmony_ci		yres = 400;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/* 2 planes must use STE compatibility mode */
9898c2ecf20Sopenharmony_ci	par->hw.falcon.ste_mode = bpp == 2;
9908c2ecf20Sopenharmony_ci	par->hw.falcon.mono = bpp == 1;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	/* Total and visible scanline length must be a multiple of one longword,
9938c2ecf20Sopenharmony_ci	 * this and the console fontwidth yields the alignment for xres and
9948c2ecf20Sopenharmony_ci	 * xres_virtual.
9958c2ecf20Sopenharmony_ci	 * TODO: this way "odd" fontheights are not supported
9968c2ecf20Sopenharmony_ci	 *
9978c2ecf20Sopenharmony_ci	 * Special case in STE mode: blank and graphic positions don't align,
9988c2ecf20Sopenharmony_ci	 * avoid trash at right margin
9998c2ecf20Sopenharmony_ci	 */
10008c2ecf20Sopenharmony_ci	if (par->hw.falcon.ste_mode)
10018c2ecf20Sopenharmony_ci		xres = (xres + 63) & ~63;
10028c2ecf20Sopenharmony_ci	else if (bpp == 1)
10038c2ecf20Sopenharmony_ci		xres = (xres + 31) & ~31;
10048c2ecf20Sopenharmony_ci	else
10058c2ecf20Sopenharmony_ci		xres = (xres + 15) & ~15;
10068c2ecf20Sopenharmony_ci	if (yres >= 400)
10078c2ecf20Sopenharmony_ci		yres = (yres + 15) & ~15;
10088c2ecf20Sopenharmony_ci	else
10098c2ecf20Sopenharmony_ci		yres = (yres + 7) & ~7;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (xres_virtual < xres)
10128c2ecf20Sopenharmony_ci		xres_virtual = xres;
10138c2ecf20Sopenharmony_ci	else if (bpp == 1)
10148c2ecf20Sopenharmony_ci		xres_virtual = (xres_virtual + 31) & ~31;
10158c2ecf20Sopenharmony_ci	else
10168c2ecf20Sopenharmony_ci		xres_virtual = (xres_virtual + 15) & ~15;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	if (yres_virtual <= 0)
10198c2ecf20Sopenharmony_ci		yres_virtual = 0;
10208c2ecf20Sopenharmony_ci	else if (yres_virtual < yres)
10218c2ecf20Sopenharmony_ci		yres_virtual = yres;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	/* backward bug-compatibility */
10248c2ecf20Sopenharmony_ci	if (var->pixclock > 1)
10258c2ecf20Sopenharmony_ci		var->pixclock -= 1;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	par->hw.falcon.line_width = bpp * xres / 16;
10288c2ecf20Sopenharmony_ci	par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	/* single or double pixel width */
10318c2ecf20Sopenharmony_ci	xstretch = (xres < 640) ? 2 : 1;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci#if 0 /* SM124 supports only 640x400, this is rejected above */
10348c2ecf20Sopenharmony_ci	if (mon_type == F_MON_SM) {
10358c2ecf20Sopenharmony_ci		if (xres != 640 && yres != 400)
10368c2ecf20Sopenharmony_ci			return -EINVAL;
10378c2ecf20Sopenharmony_ci		plen = 1;
10388c2ecf20Sopenharmony_ci		pclock = &f32;
10398c2ecf20Sopenharmony_ci		/* SM124-mode is special */
10408c2ecf20Sopenharmony_ci		par->hw.falcon.ste_mode = 1;
10418c2ecf20Sopenharmony_ci		par->hw.falcon.f_shift = 0x000;
10428c2ecf20Sopenharmony_ci		par->hw.falcon.st_shift = 0x200;
10438c2ecf20Sopenharmony_ci		left_margin = hsync_len = 128 / plen;
10448c2ecf20Sopenharmony_ci		right_margin = 0;
10458c2ecf20Sopenharmony_ci		/* TODO set all margins */
10468c2ecf20Sopenharmony_ci	} else
10478c2ecf20Sopenharmony_ci#endif
10488c2ecf20Sopenharmony_ci	if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
10498c2ecf20Sopenharmony_ci		plen = 2 * xstretch;
10508c2ecf20Sopenharmony_ci		if (var->pixclock > f32.t * plen)
10518c2ecf20Sopenharmony_ci			return -EINVAL;
10528c2ecf20Sopenharmony_ci		pclock = &f32;
10538c2ecf20Sopenharmony_ci		if (yres > 240)
10548c2ecf20Sopenharmony_ci			interlace = 1;
10558c2ecf20Sopenharmony_ci		if (var->pixclock == 0) {
10568c2ecf20Sopenharmony_ci			/* set some minimal margins which center the screen */
10578c2ecf20Sopenharmony_ci			left_margin = 32;
10588c2ecf20Sopenharmony_ci			right_margin = 18;
10598c2ecf20Sopenharmony_ci			hsync_len = pclock->hsync / plen;
10608c2ecf20Sopenharmony_ci			upper_margin = 31;
10618c2ecf20Sopenharmony_ci			lower_margin = 14;
10628c2ecf20Sopenharmony_ci			vsync_len = interlace ? 3 : 4;
10638c2ecf20Sopenharmony_ci		} else {
10648c2ecf20Sopenharmony_ci			left_margin = var->left_margin;
10658c2ecf20Sopenharmony_ci			right_margin = var->right_margin;
10668c2ecf20Sopenharmony_ci			hsync_len = var->hsync_len;
10678c2ecf20Sopenharmony_ci			upper_margin = var->upper_margin;
10688c2ecf20Sopenharmony_ci			lower_margin = var->lower_margin;
10698c2ecf20Sopenharmony_ci			vsync_len = var->vsync_len;
10708c2ecf20Sopenharmony_ci			if (var->vmode & FB_VMODE_INTERLACED) {
10718c2ecf20Sopenharmony_ci				upper_margin = (upper_margin + 1) / 2;
10728c2ecf20Sopenharmony_ci				lower_margin = (lower_margin + 1) / 2;
10738c2ecf20Sopenharmony_ci				vsync_len = (vsync_len + 1) / 2;
10748c2ecf20Sopenharmony_ci			} else if (var->vmode & FB_VMODE_DOUBLE) {
10758c2ecf20Sopenharmony_ci				upper_margin *= 2;
10768c2ecf20Sopenharmony_ci				lower_margin *= 2;
10778c2ecf20Sopenharmony_ci				vsync_len *= 2;
10788c2ecf20Sopenharmony_ci			}
10798c2ecf20Sopenharmony_ci		}
10808c2ecf20Sopenharmony_ci	} else {			/* F_MON_VGA */
10818c2ecf20Sopenharmony_ci		if (bpp == 16)
10828c2ecf20Sopenharmony_ci			xstretch = 2;	/* Double pixel width only for hicolor */
10838c2ecf20Sopenharmony_ci		/* Default values are used for vert./hor. timing if no pixelclock given. */
10848c2ecf20Sopenharmony_ci		if (var->pixclock == 0) {
10858c2ecf20Sopenharmony_ci			int linesize;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci			/* Choose master pixelclock depending on hor. timing */
10888c2ecf20Sopenharmony_ci			plen = 1 * xstretch;
10898c2ecf20Sopenharmony_ci			if ((plen * xres + f25.right + f25.hsync + f25.left) *
10908c2ecf20Sopenharmony_ci			    fb_info.monspecs.hfmin < f25.f)
10918c2ecf20Sopenharmony_ci				pclock = &f25;
10928c2ecf20Sopenharmony_ci			else if ((plen * xres + f32.right + f32.hsync +
10938c2ecf20Sopenharmony_ci				  f32.left) * fb_info.monspecs.hfmin < f32.f)
10948c2ecf20Sopenharmony_ci				pclock = &f32;
10958c2ecf20Sopenharmony_ci			else if ((plen * xres + fext.right + fext.hsync +
10968c2ecf20Sopenharmony_ci				  fext.left) * fb_info.monspecs.hfmin < fext.f &&
10978c2ecf20Sopenharmony_ci			         fext.f)
10988c2ecf20Sopenharmony_ci				pclock = &fext;
10998c2ecf20Sopenharmony_ci			else
11008c2ecf20Sopenharmony_ci				return -EINVAL;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci			left_margin = pclock->left / plen;
11038c2ecf20Sopenharmony_ci			right_margin = pclock->right / plen;
11048c2ecf20Sopenharmony_ci			hsync_len = pclock->hsync / plen;
11058c2ecf20Sopenharmony_ci			linesize = left_margin + xres + right_margin + hsync_len;
11068c2ecf20Sopenharmony_ci			upper_margin = 31;
11078c2ecf20Sopenharmony_ci			lower_margin = 11;
11088c2ecf20Sopenharmony_ci			vsync_len = 3;
11098c2ecf20Sopenharmony_ci		} else {
11108c2ecf20Sopenharmony_ci			/* Choose largest pixelclock <= wanted clock */
11118c2ecf20Sopenharmony_ci			int i;
11128c2ecf20Sopenharmony_ci			unsigned long pcl = ULONG_MAX;
11138c2ecf20Sopenharmony_ci			pclock = 0;
11148c2ecf20Sopenharmony_ci			for (i = 1; i <= 4; i *= 2) {
11158c2ecf20Sopenharmony_ci				if (f25.t * i >= var->pixclock &&
11168c2ecf20Sopenharmony_ci				    f25.t * i < pcl) {
11178c2ecf20Sopenharmony_ci					pcl = f25.t * i;
11188c2ecf20Sopenharmony_ci					pclock = &f25;
11198c2ecf20Sopenharmony_ci				}
11208c2ecf20Sopenharmony_ci				if (f32.t * i >= var->pixclock &&
11218c2ecf20Sopenharmony_ci				    f32.t * i < pcl) {
11228c2ecf20Sopenharmony_ci					pcl = f32.t * i;
11238c2ecf20Sopenharmony_ci					pclock = &f32;
11248c2ecf20Sopenharmony_ci				}
11258c2ecf20Sopenharmony_ci				if (fext.t && fext.t * i >= var->pixclock &&
11268c2ecf20Sopenharmony_ci				    fext.t * i < pcl) {
11278c2ecf20Sopenharmony_ci					pcl = fext.t * i;
11288c2ecf20Sopenharmony_ci					pclock = &fext;
11298c2ecf20Sopenharmony_ci				}
11308c2ecf20Sopenharmony_ci			}
11318c2ecf20Sopenharmony_ci			if (!pclock)
11328c2ecf20Sopenharmony_ci				return -EINVAL;
11338c2ecf20Sopenharmony_ci			plen = pcl / pclock->t;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci			left_margin = var->left_margin;
11368c2ecf20Sopenharmony_ci			right_margin = var->right_margin;
11378c2ecf20Sopenharmony_ci			hsync_len = var->hsync_len;
11388c2ecf20Sopenharmony_ci			upper_margin = var->upper_margin;
11398c2ecf20Sopenharmony_ci			lower_margin = var->lower_margin;
11408c2ecf20Sopenharmony_ci			vsync_len = var->vsync_len;
11418c2ecf20Sopenharmony_ci			/* Internal unit is [single lines per (half-)frame] */
11428c2ecf20Sopenharmony_ci			if (var->vmode & FB_VMODE_INTERLACED) {
11438c2ecf20Sopenharmony_ci				/* # lines in half frame */
11448c2ecf20Sopenharmony_ci				/* External unit is [lines per full frame] */
11458c2ecf20Sopenharmony_ci				upper_margin = (upper_margin + 1) / 2;
11468c2ecf20Sopenharmony_ci				lower_margin = (lower_margin + 1) / 2;
11478c2ecf20Sopenharmony_ci				vsync_len = (vsync_len + 1) / 2;
11488c2ecf20Sopenharmony_ci			} else if (var->vmode & FB_VMODE_DOUBLE) {
11498c2ecf20Sopenharmony_ci				/* External unit is [double lines per frame] */
11508c2ecf20Sopenharmony_ci				upper_margin *= 2;
11518c2ecf20Sopenharmony_ci				lower_margin *= 2;
11528c2ecf20Sopenharmony_ci				vsync_len *= 2;
11538c2ecf20Sopenharmony_ci			}
11548c2ecf20Sopenharmony_ci		}
11558c2ecf20Sopenharmony_ci		if (pclock == &fext)
11568c2ecf20Sopenharmony_ci			longoffset = 1;	/* VIDEL doesn't synchronize on short offset */
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci	/* Is video bus bandwidth (32MB/s) too low for this resolution? */
11598c2ecf20Sopenharmony_ci	/* this is definitely wrong if bus clock != 32MHz */
11608c2ecf20Sopenharmony_ci	if (pclock->f / plen / 8 * bpp > 32000000L)
11618c2ecf20Sopenharmony_ci		return -EINVAL;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	if (vsync_len < 1)
11648c2ecf20Sopenharmony_ci		vsync_len = 1;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	/* include sync lengths in right/lower margin for all calculations */
11678c2ecf20Sopenharmony_ci	right_margin += hsync_len;
11688c2ecf20Sopenharmony_ci	lower_margin += vsync_len;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	/* ! In all calculations of margins we use # of lines in half frame
11718c2ecf20Sopenharmony_ci	 * (which is a full frame in non-interlace mode), so we can switch
11728c2ecf20Sopenharmony_ci	 * between interlace and non-interlace without messing around
11738c2ecf20Sopenharmony_ci	 * with these.
11748c2ecf20Sopenharmony_ci	 */
11758c2ecf20Sopenharmony_ciagain:
11768c2ecf20Sopenharmony_ci	/* Set base_offset 128 and video bus width */
11778c2ecf20Sopenharmony_ci	par->hw.falcon.vid_control = mon_type | f030_bus_width;
11788c2ecf20Sopenharmony_ci	if (!longoffset)
11798c2ecf20Sopenharmony_ci		par->hw.falcon.vid_control |= VCO_SHORTOFFS;	/* base_offset 64 */
11808c2ecf20Sopenharmony_ci	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
11818c2ecf20Sopenharmony_ci		par->hw.falcon.vid_control |= VCO_HSYPOS;
11828c2ecf20Sopenharmony_ci	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
11838c2ecf20Sopenharmony_ci		par->hw.falcon.vid_control |= VCO_VSYPOS;
11848c2ecf20Sopenharmony_ci	/* Pixelclock */
11858c2ecf20Sopenharmony_ci	par->hw.falcon.vid_control |= pclock->control_mask;
11868c2ecf20Sopenharmony_ci	/* External or internal clock */
11878c2ecf20Sopenharmony_ci	par->hw.falcon.sync = pclock->sync_mask | 0x2;
11888c2ecf20Sopenharmony_ci	/* Pixellength and prescale */
11898c2ecf20Sopenharmony_ci	par->hw.falcon.vid_mode = (2 / plen) << 2;
11908c2ecf20Sopenharmony_ci	if (doubleline)
11918c2ecf20Sopenharmony_ci		par->hw.falcon.vid_mode |= VMO_DOUBLE;
11928c2ecf20Sopenharmony_ci	if (interlace)
11938c2ecf20Sopenharmony_ci		par->hw.falcon.vid_mode |= VMO_INTER;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	/*********************
11968c2ecf20Sopenharmony_ci	 * Horizontal timing: unit = [master clock cycles]
11978c2ecf20Sopenharmony_ci	 * unit of hxx-registers: [master clock cycles * prescale]
11988c2ecf20Sopenharmony_ci	 * Hxx-registers are 9 bit wide
11998c2ecf20Sopenharmony_ci	 *
12008c2ecf20Sopenharmony_ci	 * 1 line = ((hht + 2) * 2 * prescale) clock cycles
12018c2ecf20Sopenharmony_ci	 *
12028c2ecf20Sopenharmony_ci	 * graphic output = hdb & 0x200 ?
12038c2ecf20Sopenharmony_ci	 *        ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff:
12048c2ecf20Sopenharmony_ci	 *        (hht + 2  - hdb + hde) * prescale - hdboff + hdeoff
12058c2ecf20Sopenharmony_ci	 * (this must be a multiple of plen*128/bpp, on VGA pixels
12068c2ecf20Sopenharmony_ci	 *  to the right may be cut off with a bigger right margin)
12078c2ecf20Sopenharmony_ci	 *
12088c2ecf20Sopenharmony_ci	 * start of graphics relative to start of 1st halfline = hdb & 0x200 ?
12098c2ecf20Sopenharmony_ci	 *        (hdb - hht - 2) * prescale + hdboff :
12108c2ecf20Sopenharmony_ci	 *        hdb * prescale + hdboff
12118c2ecf20Sopenharmony_ci	 *
12128c2ecf20Sopenharmony_ci	 * end of graphics relative to start of 1st halfline =
12138c2ecf20Sopenharmony_ci	 *        (hde + hht + 2) * prescale + hdeoff
12148c2ecf20Sopenharmony_ci	 *********************/
12158c2ecf20Sopenharmony_ci	/* Calculate VIDEL registers */
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	prescale = hxx_prescale(&par->hw.falcon);
12188c2ecf20Sopenharmony_ci	base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	/* Offsets depend on video mode */
12218c2ecf20Sopenharmony_ci	/* Offsets are in clock cycles, divide by prescale to
12228c2ecf20Sopenharmony_ci	 * calculate hd[be]-registers
12238c2ecf20Sopenharmony_ci	 */
12248c2ecf20Sopenharmony_ci	if (par->hw.falcon.f_shift & 0x100) {
12258c2ecf20Sopenharmony_ci		align = 1;
12268c2ecf20Sopenharmony_ci		hde_off = 0;
12278c2ecf20Sopenharmony_ci		hdb_off = (base_off + 16 * plen) + prescale;
12288c2ecf20Sopenharmony_ci	} else {
12298c2ecf20Sopenharmony_ci		align = 128 / bpp;
12308c2ecf20Sopenharmony_ci		hde_off = ((128 / bpp + 2) * plen);
12318c2ecf20Sopenharmony_ci		if (par->hw.falcon.ste_mode)
12328c2ecf20Sopenharmony_ci			hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
12338c2ecf20Sopenharmony_ci		else
12348c2ecf20Sopenharmony_ci			hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
12358c2ecf20Sopenharmony_ci	}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	gstart = (prescale / 2 + plen * left_margin) / prescale;
12388c2ecf20Sopenharmony_ci	/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
12398c2ecf20Sopenharmony_ci	gend1 = gstart + roundup(xres, align) * plen / prescale;
12408c2ecf20Sopenharmony_ci	/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
12418c2ecf20Sopenharmony_ci	gend2 = gstart + xres * plen / prescale;
12428c2ecf20Sopenharmony_ci	par->HHT = plen * (left_margin + xres + right_margin) /
12438c2ecf20Sopenharmony_ci			   (2 * prescale) - 2;
12448c2ecf20Sopenharmony_ci/*	par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	par->HDB = gstart - hdb_off / prescale;
12478c2ecf20Sopenharmony_ci	par->HBE = gstart;
12488c2ecf20Sopenharmony_ci	if (par->HDB < 0)
12498c2ecf20Sopenharmony_ci		par->HDB += par->HHT + 2 + 0x200;
12508c2ecf20Sopenharmony_ci	par->HDE = gend1 - par->HHT - 2 - hde_off / prescale;
12518c2ecf20Sopenharmony_ci	par->HBB = gend2 - par->HHT - 2;
12528c2ecf20Sopenharmony_ci#if 0
12538c2ecf20Sopenharmony_ci	/* One more Videl constraint: data fetch of two lines must not overlap */
12548c2ecf20Sopenharmony_ci	if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
12558c2ecf20Sopenharmony_ci		/* if this happens increase margins, decrease hfreq. */
12568c2ecf20Sopenharmony_ci	}
12578c2ecf20Sopenharmony_ci#endif
12588c2ecf20Sopenharmony_ci	if (hde_off % prescale)
12598c2ecf20Sopenharmony_ci		par->HBB++;		/* compensate for non matching hde and hbb */
12608c2ecf20Sopenharmony_ci	par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
12618c2ecf20Sopenharmony_ci	if (par->HSS < par->HBB)
12628c2ecf20Sopenharmony_ci		par->HSS = par->HBB;
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	/*  check hor. frequency */
12668c2ecf20Sopenharmony_ci	hfreq = pclock->f / ((par->HHT + 2) * prescale * 2);
12678c2ecf20Sopenharmony_ci	if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) {
12688c2ecf20Sopenharmony_ci		/* ++guenther:   ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
12698c2ecf20Sopenharmony_ci		/* Too high -> enlarge margin */
12708c2ecf20Sopenharmony_ci		left_margin += 1;
12718c2ecf20Sopenharmony_ci		right_margin += 1;
12728c2ecf20Sopenharmony_ci		goto again;
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci	if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin)
12758c2ecf20Sopenharmony_ci		return -EINVAL;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	/* Vxx-registers */
12788c2ecf20Sopenharmony_ci	/* All Vxx must be odd in non-interlace, since frame starts in the middle
12798c2ecf20Sopenharmony_ci	 * of the first displayed line!
12808c2ecf20Sopenharmony_ci	 * One frame consists of VFT+1 half lines. VFT+1 must be even in
12818c2ecf20Sopenharmony_ci	 * non-interlace, odd in interlace mode for synchronisation.
12828c2ecf20Sopenharmony_ci	 * Vxx-registers are 11 bit wide
12838c2ecf20Sopenharmony_ci	 */
12848c2ecf20Sopenharmony_ci	par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
12858c2ecf20Sopenharmony_ci	par->VDB = par->VBE;
12868c2ecf20Sopenharmony_ci	par->VDE = yres;
12878c2ecf20Sopenharmony_ci	if (!interlace)
12888c2ecf20Sopenharmony_ci		par->VDE <<= 1;
12898c2ecf20Sopenharmony_ci	if (doubleline)
12908c2ecf20Sopenharmony_ci		par->VDE <<= 1;		/* VDE now half lines per (half-)frame */
12918c2ecf20Sopenharmony_ci	par->VDE += par->VDB;
12928c2ecf20Sopenharmony_ci	par->VBB = par->VDE;
12938c2ecf20Sopenharmony_ci	par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
12948c2ecf20Sopenharmony_ci	par->VSS = par->VFT + 1 - (vsync_len * 2 - 1);
12958c2ecf20Sopenharmony_ci	/* vbb,vss,vft must be even in interlace mode */
12968c2ecf20Sopenharmony_ci	if (interlace) {
12978c2ecf20Sopenharmony_ci		par->VBB++;
12988c2ecf20Sopenharmony_ci		par->VSS++;
12998c2ecf20Sopenharmony_ci		par->VFT++;
13008c2ecf20Sopenharmony_ci	}
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	/* V-frequency check, hope I didn't create any loop here. */
13038c2ecf20Sopenharmony_ci	/* Interlace and doubleline are mutually exclusive. */
13048c2ecf20Sopenharmony_ci	vfreq = (hfreq * 2) / (par->VFT + 1);
13058c2ecf20Sopenharmony_ci	if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
13068c2ecf20Sopenharmony_ci		/* Too high -> try again with doubleline */
13078c2ecf20Sopenharmony_ci		doubleline = 1;
13088c2ecf20Sopenharmony_ci		goto again;
13098c2ecf20Sopenharmony_ci	} else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
13108c2ecf20Sopenharmony_ci		/* Too low -> try again with interlace */
13118c2ecf20Sopenharmony_ci		interlace = 1;
13128c2ecf20Sopenharmony_ci		goto again;
13138c2ecf20Sopenharmony_ci	} else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
13148c2ecf20Sopenharmony_ci		/* Doubleline too low -> clear doubleline and enlarge margins */
13158c2ecf20Sopenharmony_ci		int lines;
13168c2ecf20Sopenharmony_ci		doubleline = 0;
13178c2ecf20Sopenharmony_ci		for (lines = 0;
13188c2ecf20Sopenharmony_ci		     (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) >
13198c2ecf20Sopenharmony_ci		     fb_info.monspecs.vfmax;
13208c2ecf20Sopenharmony_ci		     lines++)
13218c2ecf20Sopenharmony_ci			;
13228c2ecf20Sopenharmony_ci		upper_margin += lines;
13238c2ecf20Sopenharmony_ci		lower_margin += lines;
13248c2ecf20Sopenharmony_ci		goto again;
13258c2ecf20Sopenharmony_ci	} else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
13268c2ecf20Sopenharmony_ci		/* Doubleline too high -> enlarge margins */
13278c2ecf20Sopenharmony_ci		int lines;
13288c2ecf20Sopenharmony_ci		for (lines = 0;
13298c2ecf20Sopenharmony_ci		     (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
13308c2ecf20Sopenharmony_ci		     fb_info.monspecs.vfmax;
13318c2ecf20Sopenharmony_ci		     lines += 2)
13328c2ecf20Sopenharmony_ci			;
13338c2ecf20Sopenharmony_ci		upper_margin += lines;
13348c2ecf20Sopenharmony_ci		lower_margin += lines;
13358c2ecf20Sopenharmony_ci		goto again;
13368c2ecf20Sopenharmony_ci	} else if (vfreq > fb_info.monspecs.vfmax && interlace) {
13378c2ecf20Sopenharmony_ci		/* Interlace, too high -> enlarge margins */
13388c2ecf20Sopenharmony_ci		int lines;
13398c2ecf20Sopenharmony_ci		for (lines = 0;
13408c2ecf20Sopenharmony_ci		     (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
13418c2ecf20Sopenharmony_ci		     fb_info.monspecs.vfmax;
13428c2ecf20Sopenharmony_ci		     lines++)
13438c2ecf20Sopenharmony_ci			;
13448c2ecf20Sopenharmony_ci		upper_margin += lines;
13458c2ecf20Sopenharmony_ci		lower_margin += lines;
13468c2ecf20Sopenharmony_ci		goto again;
13478c2ecf20Sopenharmony_ci	} else if (vfreq < fb_info.monspecs.vfmin ||
13488c2ecf20Sopenharmony_ci		   vfreq > fb_info.monspecs.vfmax)
13498c2ecf20Sopenharmony_ci		return -EINVAL;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ciset_screen_base:
13528c2ecf20Sopenharmony_ci	linelen = xres_virtual * bpp / 8;
13538c2ecf20Sopenharmony_ci	if (yres_virtual * linelen > screen_len && screen_len)
13548c2ecf20Sopenharmony_ci		return -EINVAL;
13558c2ecf20Sopenharmony_ci	if (yres * linelen > screen_len && screen_len)
13568c2ecf20Sopenharmony_ci		return -EINVAL;
13578c2ecf20Sopenharmony_ci	if (var->yoffset + yres > yres_virtual && yres_virtual)
13588c2ecf20Sopenharmony_ci		return -EINVAL;
13598c2ecf20Sopenharmony_ci	par->yres_virtual = yres_virtual;
13608c2ecf20Sopenharmony_ci	par->screen_base = screen_base + var->yoffset * linelen;
13618c2ecf20Sopenharmony_ci	par->hw.falcon.xoffset = 0;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	par->next_line = linelen;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	return 0;
13668c2ecf20Sopenharmony_ci}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_cistatic int falcon_encode_var(struct fb_var_screeninfo *var,
13698c2ecf20Sopenharmony_ci			     struct atafb_par *par)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci/* !!! only for VGA !!! */
13728c2ecf20Sopenharmony_ci	int linelen;
13738c2ecf20Sopenharmony_ci	int prescale, plen;
13748c2ecf20Sopenharmony_ci	int hdb_off, hde_off, base_off;
13758c2ecf20Sopenharmony_ci	struct falcon_hw *hw = &par->hw.falcon;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	memset(var, 0, sizeof(struct fb_var_screeninfo));
13788c2ecf20Sopenharmony_ci	/* possible frequencies: 25.175 or 32MHz */
13798c2ecf20Sopenharmony_ci	var->pixclock = hw->sync & 0x1 ? fext.t :
13808c2ecf20Sopenharmony_ci	                hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	var->height = -1;
13838c2ecf20Sopenharmony_ci	var->width = -1;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	var->sync = 0;
13868c2ecf20Sopenharmony_ci	if (hw->vid_control & VCO_HSYPOS)
13878c2ecf20Sopenharmony_ci		var->sync |= FB_SYNC_HOR_HIGH_ACT;
13888c2ecf20Sopenharmony_ci	if (hw->vid_control & VCO_VSYPOS)
13898c2ecf20Sopenharmony_ci		var->sync |= FB_SYNC_VERT_HIGH_ACT;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	var->vmode = FB_VMODE_NONINTERLACED;
13928c2ecf20Sopenharmony_ci	if (hw->vid_mode & VMO_INTER)
13938c2ecf20Sopenharmony_ci		var->vmode |= FB_VMODE_INTERLACED;
13948c2ecf20Sopenharmony_ci	if (hw->vid_mode & VMO_DOUBLE)
13958c2ecf20Sopenharmony_ci		var->vmode |= FB_VMODE_DOUBLE;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	/* visible y resolution:
13988c2ecf20Sopenharmony_ci	 * Graphics display starts at line VDB and ends at line
13998c2ecf20Sopenharmony_ci	 * VDE. If interlace mode off unit of VC-registers is
14008c2ecf20Sopenharmony_ci	 * half lines, else lines.
14018c2ecf20Sopenharmony_ci	 */
14028c2ecf20Sopenharmony_ci	var->yres = hw->vde - hw->vdb;
14038c2ecf20Sopenharmony_ci	if (!(var->vmode & FB_VMODE_INTERLACED))
14048c2ecf20Sopenharmony_ci		var->yres >>= 1;
14058c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE)
14068c2ecf20Sopenharmony_ci		var->yres >>= 1;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	/*
14098c2ecf20Sopenharmony_ci	 * to get bpp, we must examine f_shift and st_shift.
14108c2ecf20Sopenharmony_ci	 * f_shift is valid if any of bits no. 10, 8 or 4
14118c2ecf20Sopenharmony_ci	 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
14128c2ecf20Sopenharmony_ci	 * if bit 10 set then bit 8 and bit 4 don't care...
14138c2ecf20Sopenharmony_ci	 * If all these bits are 0 get display depth from st_shift
14148c2ecf20Sopenharmony_ci	 * (as for ST and STE)
14158c2ecf20Sopenharmony_ci	 */
14168c2ecf20Sopenharmony_ci	if (hw->f_shift & 0x400)	/* 2 colors */
14178c2ecf20Sopenharmony_ci		var->bits_per_pixel = 1;
14188c2ecf20Sopenharmony_ci	else if (hw->f_shift & 0x100)	/* hicolor */
14198c2ecf20Sopenharmony_ci		var->bits_per_pixel = 16;
14208c2ecf20Sopenharmony_ci	else if (hw->f_shift & 0x010)	/* 8 bitplanes */
14218c2ecf20Sopenharmony_ci		var->bits_per_pixel = 8;
14228c2ecf20Sopenharmony_ci	else if (hw->st_shift == 0)
14238c2ecf20Sopenharmony_ci		var->bits_per_pixel = 4;
14248c2ecf20Sopenharmony_ci	else if (hw->st_shift == 0x100)
14258c2ecf20Sopenharmony_ci		var->bits_per_pixel = 2;
14268c2ecf20Sopenharmony_ci	else				/* if (hw->st_shift == 0x200) */
14278c2ecf20Sopenharmony_ci		var->bits_per_pixel = 1;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	var->xres = hw->line_width * 16 / var->bits_per_pixel;
14308c2ecf20Sopenharmony_ci	var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
14318c2ecf20Sopenharmony_ci	if (hw->xoffset)
14328c2ecf20Sopenharmony_ci		var->xres_virtual += 16;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	if (var->bits_per_pixel == 16) {
14358c2ecf20Sopenharmony_ci		var->red.offset = 11;
14368c2ecf20Sopenharmony_ci		var->red.length = 5;
14378c2ecf20Sopenharmony_ci		var->red.msb_right = 0;
14388c2ecf20Sopenharmony_ci		var->green.offset = 5;
14398c2ecf20Sopenharmony_ci		var->green.length = 6;
14408c2ecf20Sopenharmony_ci		var->green.msb_right = 0;
14418c2ecf20Sopenharmony_ci		var->blue.offset = 0;
14428c2ecf20Sopenharmony_ci		var->blue.length = 5;
14438c2ecf20Sopenharmony_ci		var->blue.msb_right = 0;
14448c2ecf20Sopenharmony_ci	} else {
14458c2ecf20Sopenharmony_ci		var->red.offset = 0;
14468c2ecf20Sopenharmony_ci		var->red.length = hw->ste_mode ? 4 : 6;
14478c2ecf20Sopenharmony_ci		if (var->red.length > var->bits_per_pixel)
14488c2ecf20Sopenharmony_ci			var->red.length = var->bits_per_pixel;
14498c2ecf20Sopenharmony_ci		var->red.msb_right = 0;
14508c2ecf20Sopenharmony_ci		var->grayscale = 0;
14518c2ecf20Sopenharmony_ci		var->blue = var->green = var->red;
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci	var->transp.offset = 0;
14548c2ecf20Sopenharmony_ci	var->transp.length = 0;
14558c2ecf20Sopenharmony_ci	var->transp.msb_right = 0;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	linelen = var->xres_virtual * var->bits_per_pixel / 8;
14588c2ecf20Sopenharmony_ci	if (screen_len) {
14598c2ecf20Sopenharmony_ci		if (par->yres_virtual)
14608c2ecf20Sopenharmony_ci			var->yres_virtual = par->yres_virtual;
14618c2ecf20Sopenharmony_ci		else
14628c2ecf20Sopenharmony_ci			/* yres_virtual == 0 means use maximum */
14638c2ecf20Sopenharmony_ci			var->yres_virtual = screen_len / linelen;
14648c2ecf20Sopenharmony_ci	} else {
14658c2ecf20Sopenharmony_ci		if (hwscroll < 0)
14668c2ecf20Sopenharmony_ci			var->yres_virtual = 2 * var->yres;
14678c2ecf20Sopenharmony_ci		else
14688c2ecf20Sopenharmony_ci			var->yres_virtual = var->yres + hwscroll * 16;
14698c2ecf20Sopenharmony_ci	}
14708c2ecf20Sopenharmony_ci	var->xoffset = 0;		/* TODO change this */
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	/* hdX-offsets */
14738c2ecf20Sopenharmony_ci	prescale = hxx_prescale(hw);
14748c2ecf20Sopenharmony_ci	plen = 4 >> (hw->vid_mode >> 2 & 0x3);
14758c2ecf20Sopenharmony_ci	base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
14768c2ecf20Sopenharmony_ci	if (hw->f_shift & 0x100) {
14778c2ecf20Sopenharmony_ci		hde_off = 0;
14788c2ecf20Sopenharmony_ci		hdb_off = (base_off + 16 * plen) + prescale;
14798c2ecf20Sopenharmony_ci	} else {
14808c2ecf20Sopenharmony_ci		hde_off = ((128 / var->bits_per_pixel + 2) * plen);
14818c2ecf20Sopenharmony_ci		if (hw->ste_mode)
14828c2ecf20Sopenharmony_ci			hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
14838c2ecf20Sopenharmony_ci					 + prescale;
14848c2ecf20Sopenharmony_ci		else
14858c2ecf20Sopenharmony_ci			hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
14868c2ecf20Sopenharmony_ci					 + prescale;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	/* Right margin includes hsync */
14908c2ecf20Sopenharmony_ci	var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
14918c2ecf20Sopenharmony_ci					   (hw->hdb & 0x200 ? 2 + hw->hht : 0));
14928c2ecf20Sopenharmony_ci	if (hw->ste_mode || mon_type != F_MON_VGA)
14938c2ecf20Sopenharmony_ci		var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
14948c2ecf20Sopenharmony_ci	else
14958c2ecf20Sopenharmony_ci		/* can't use this in ste_mode, because hbb is +1 off */
14968c2ecf20Sopenharmony_ci		var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
14978c2ecf20Sopenharmony_ci	var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	/* Lower margin includes vsync */
15008c2ecf20Sopenharmony_ci	var->upper_margin = hw->vdb / 2;	/* round down to full lines */
15018c2ecf20Sopenharmony_ci	var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2;	/* round up */
15028c2ecf20Sopenharmony_ci	var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2;	/* round up */
15038c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED) {
15048c2ecf20Sopenharmony_ci		var->upper_margin *= 2;
15058c2ecf20Sopenharmony_ci		var->lower_margin *= 2;
15068c2ecf20Sopenharmony_ci		var->vsync_len *= 2;
15078c2ecf20Sopenharmony_ci	} else if (var->vmode & FB_VMODE_DOUBLE) {
15088c2ecf20Sopenharmony_ci		var->upper_margin = (var->upper_margin + 1) / 2;
15098c2ecf20Sopenharmony_ci		var->lower_margin = (var->lower_margin + 1) / 2;
15108c2ecf20Sopenharmony_ci		var->vsync_len = (var->vsync_len + 1) / 2;
15118c2ecf20Sopenharmony_ci	}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	var->pixclock *= plen;
15148c2ecf20Sopenharmony_ci	var->left_margin /= plen;
15158c2ecf20Sopenharmony_ci	var->right_margin /= plen;
15168c2ecf20Sopenharmony_ci	var->hsync_len /= plen;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	var->right_margin -= var->hsync_len;
15198c2ecf20Sopenharmony_ci	var->lower_margin -= var->vsync_len;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	if (screen_base)
15228c2ecf20Sopenharmony_ci		var->yoffset = (par->screen_base - screen_base) / linelen;
15238c2ecf20Sopenharmony_ci	else
15248c2ecf20Sopenharmony_ci		var->yoffset = 0;
15258c2ecf20Sopenharmony_ci	var->nonstd = 0;		/* what is this for? */
15268c2ecf20Sopenharmony_ci	var->activate = 0;
15278c2ecf20Sopenharmony_ci	return 0;
15288c2ecf20Sopenharmony_ci}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_cistatic int f_change_mode;
15318c2ecf20Sopenharmony_cistatic struct falcon_hw f_new_mode;
15328c2ecf20Sopenharmony_cistatic int f_pan_display;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cistatic void falcon_get_par(struct atafb_par *par)
15358c2ecf20Sopenharmony_ci{
15368c2ecf20Sopenharmony_ci	unsigned long addr;
15378c2ecf20Sopenharmony_ci	struct falcon_hw *hw = &par->hw.falcon;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	hw->line_width = shifter_f030.scn_width;
15408c2ecf20Sopenharmony_ci	hw->line_offset = shifter_f030.off_next;
15418c2ecf20Sopenharmony_ci	hw->st_shift = videl.st_shift & 0x300;
15428c2ecf20Sopenharmony_ci	hw->f_shift = videl.f_shift;
15438c2ecf20Sopenharmony_ci	hw->vid_control = videl.control;
15448c2ecf20Sopenharmony_ci	hw->vid_mode = videl.mode;
15458c2ecf20Sopenharmony_ci	hw->sync = shifter_st.syncmode & 0x1;
15468c2ecf20Sopenharmony_ci	hw->xoffset = videl.xoffset & 0xf;
15478c2ecf20Sopenharmony_ci	hw->hht = videl.hht;
15488c2ecf20Sopenharmony_ci	hw->hbb = videl.hbb;
15498c2ecf20Sopenharmony_ci	hw->hbe = videl.hbe;
15508c2ecf20Sopenharmony_ci	hw->hdb = videl.hdb;
15518c2ecf20Sopenharmony_ci	hw->hde = videl.hde;
15528c2ecf20Sopenharmony_ci	hw->hss = videl.hss;
15538c2ecf20Sopenharmony_ci	hw->vft = videl.vft;
15548c2ecf20Sopenharmony_ci	hw->vbb = videl.vbb;
15558c2ecf20Sopenharmony_ci	hw->vbe = videl.vbe;
15568c2ecf20Sopenharmony_ci	hw->vdb = videl.vdb;
15578c2ecf20Sopenharmony_ci	hw->vde = videl.vde;
15588c2ecf20Sopenharmony_ci	hw->vss = videl.vss;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	addr = (shifter_st.bas_hi & 0xff) << 16 |
15618c2ecf20Sopenharmony_ci	       (shifter_st.bas_md & 0xff) << 8  |
15628c2ecf20Sopenharmony_ci	       (shifter_st.bas_lo & 0xff);
15638c2ecf20Sopenharmony_ci	par->screen_base = atari_stram_to_virt(addr);
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	/* derived parameters */
15668c2ecf20Sopenharmony_ci	hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100;
15678c2ecf20Sopenharmony_ci	hw->mono = (hw->f_shift & 0x400) ||
15688c2ecf20Sopenharmony_ci	           ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200);
15698c2ecf20Sopenharmony_ci}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_cistatic void falcon_set_par(struct atafb_par *par)
15728c2ecf20Sopenharmony_ci{
15738c2ecf20Sopenharmony_ci	f_change_mode = 0;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	/* only set screen_base if really necessary */
15768c2ecf20Sopenharmony_ci	if (current_par.screen_base != par->screen_base)
15778c2ecf20Sopenharmony_ci		fbhw->set_screen_base(par->screen_base);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	/* Don't touch any other registers if we keep the default resolution */
15808c2ecf20Sopenharmony_ci	if (DontCalcRes)
15818c2ecf20Sopenharmony_ci		return;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	/* Tell vbl-handler to change video mode.
15848c2ecf20Sopenharmony_ci	 * We change modes only on next VBL, to avoid desynchronisation
15858c2ecf20Sopenharmony_ci	 * (a shift to the right and wrap around by a random number of pixels
15868c2ecf20Sopenharmony_ci	 * in all monochrome modes).
15878c2ecf20Sopenharmony_ci	 * This seems to work on my Falcon.
15888c2ecf20Sopenharmony_ci	 */
15898c2ecf20Sopenharmony_ci	f_new_mode = par->hw.falcon;
15908c2ecf20Sopenharmony_ci	f_change_mode = 1;
15918c2ecf20Sopenharmony_ci}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_cistatic irqreturn_t falcon_vbl_switcher(int irq, void *dummy)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct falcon_hw *hw = &f_new_mode;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	if (f_change_mode) {
15988c2ecf20Sopenharmony_ci		f_change_mode = 0;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci		if (hw->sync & 0x1) {
16018c2ecf20Sopenharmony_ci			/* Enable external pixelclock. This code only for ScreenWonder */
16028c2ecf20Sopenharmony_ci			*(volatile unsigned short *)0xffff9202 = 0xffbf;
16038c2ecf20Sopenharmony_ci		} else {
16048c2ecf20Sopenharmony_ci			/* Turn off external clocks. Read sets all output bits to 1. */
16058c2ecf20Sopenharmony_ci			*(volatile unsigned short *)0xffff9202;
16068c2ecf20Sopenharmony_ci		}
16078c2ecf20Sopenharmony_ci		shifter_st.syncmode = hw->sync;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci		videl.hht = hw->hht;
16108c2ecf20Sopenharmony_ci		videl.hbb = hw->hbb;
16118c2ecf20Sopenharmony_ci		videl.hbe = hw->hbe;
16128c2ecf20Sopenharmony_ci		videl.hdb = hw->hdb;
16138c2ecf20Sopenharmony_ci		videl.hde = hw->hde;
16148c2ecf20Sopenharmony_ci		videl.hss = hw->hss;
16158c2ecf20Sopenharmony_ci		videl.vft = hw->vft;
16168c2ecf20Sopenharmony_ci		videl.vbb = hw->vbb;
16178c2ecf20Sopenharmony_ci		videl.vbe = hw->vbe;
16188c2ecf20Sopenharmony_ci		videl.vdb = hw->vdb;
16198c2ecf20Sopenharmony_ci		videl.vde = hw->vde;
16208c2ecf20Sopenharmony_ci		videl.vss = hw->vss;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci		videl.f_shift = 0;	/* write enables Falcon palette, 0: 4 planes */
16238c2ecf20Sopenharmony_ci		if (hw->ste_mode) {
16248c2ecf20Sopenharmony_ci			videl.st_shift = hw->st_shift;	/* write enables STE palette */
16258c2ecf20Sopenharmony_ci		} else {
16268c2ecf20Sopenharmony_ci			/* IMPORTANT:
16278c2ecf20Sopenharmony_ci			 * set st_shift 0, so we can tell the screen-depth if f_shift == 0.
16288c2ecf20Sopenharmony_ci			 * Writing 0 to f_shift enables 4 plane Falcon mode but
16298c2ecf20Sopenharmony_ci			 * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible
16308c2ecf20Sopenharmony_ci			 * with Falcon palette.
16318c2ecf20Sopenharmony_ci			 */
16328c2ecf20Sopenharmony_ci			videl.st_shift = 0;
16338c2ecf20Sopenharmony_ci			/* now back to Falcon palette mode */
16348c2ecf20Sopenharmony_ci			videl.f_shift = hw->f_shift;
16358c2ecf20Sopenharmony_ci		}
16368c2ecf20Sopenharmony_ci		/* writing to st_shift changed scn_width and vid_mode */
16378c2ecf20Sopenharmony_ci		videl.xoffset = hw->xoffset;
16388c2ecf20Sopenharmony_ci		shifter_f030.scn_width = hw->line_width;
16398c2ecf20Sopenharmony_ci		shifter_f030.off_next = hw->line_offset;
16408c2ecf20Sopenharmony_ci		videl.control = hw->vid_control;
16418c2ecf20Sopenharmony_ci		videl.mode = hw->vid_mode;
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ci	if (f_pan_display) {
16448c2ecf20Sopenharmony_ci		f_pan_display = 0;
16458c2ecf20Sopenharmony_ci		videl.xoffset = current_par.hw.falcon.xoffset;
16468c2ecf20Sopenharmony_ci		shifter_f030.off_next = current_par.hw.falcon.line_offset;
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
16498c2ecf20Sopenharmony_ci}
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_cistatic int falcon_pan_display(struct fb_var_screeninfo *var,
16528c2ecf20Sopenharmony_ci			      struct fb_info *info)
16538c2ecf20Sopenharmony_ci{
16548c2ecf20Sopenharmony_ci	struct atafb_par *par = (struct atafb_par *)info->par;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	int xoffset;
16578c2ecf20Sopenharmony_ci	int bpp = info->var.bits_per_pixel;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	if (bpp == 1)
16608c2ecf20Sopenharmony_ci		var->xoffset = up(var->xoffset, 32);
16618c2ecf20Sopenharmony_ci	if (bpp != 16)
16628c2ecf20Sopenharmony_ci		par->hw.falcon.xoffset = var->xoffset & 15;
16638c2ecf20Sopenharmony_ci	else {
16648c2ecf20Sopenharmony_ci		par->hw.falcon.xoffset = 0;
16658c2ecf20Sopenharmony_ci		var->xoffset = up(var->xoffset, 2);
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci	par->hw.falcon.line_offset = bpp *
16688c2ecf20Sopenharmony_ci		(info->var.xres_virtual - info->var.xres) / 16;
16698c2ecf20Sopenharmony_ci	if (par->hw.falcon.xoffset)
16708c2ecf20Sopenharmony_ci		par->hw.falcon.line_offset -= bpp;
16718c2ecf20Sopenharmony_ci	xoffset = var->xoffset - par->hw.falcon.xoffset;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	par->screen_base = screen_base +
16748c2ecf20Sopenharmony_ci	        (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8;
16758c2ecf20Sopenharmony_ci	if (fbhw->set_screen_base)
16768c2ecf20Sopenharmony_ci		fbhw->set_screen_base(par->screen_base);
16778c2ecf20Sopenharmony_ci	else
16788c2ecf20Sopenharmony_ci		return -EINVAL;		/* shouldn't happen */
16798c2ecf20Sopenharmony_ci	f_pan_display = 1;
16808c2ecf20Sopenharmony_ci	return 0;
16818c2ecf20Sopenharmony_ci}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_cistatic int falcon_setcolreg(unsigned int regno, unsigned int red,
16848c2ecf20Sopenharmony_ci			    unsigned int green, unsigned int blue,
16858c2ecf20Sopenharmony_ci			    unsigned int transp, struct fb_info *info)
16868c2ecf20Sopenharmony_ci{
16878c2ecf20Sopenharmony_ci	if (regno > 255)
16888c2ecf20Sopenharmony_ci		return 1;
16898c2ecf20Sopenharmony_ci	f030_col[regno] = (((red & 0xfc00) << 16) |
16908c2ecf20Sopenharmony_ci			   ((green & 0xfc00) << 8) |
16918c2ecf20Sopenharmony_ci			   ((blue & 0xfc00) >> 8));
16928c2ecf20Sopenharmony_ci	if (regno < 16) {
16938c2ecf20Sopenharmony_ci		shifter_tt.color_reg[regno] =
16948c2ecf20Sopenharmony_ci			((((red & 0xe000) >> 13)   | ((red & 0x1000) >> 12)) << 8)   |
16958c2ecf20Sopenharmony_ci			((((green & 0xe000) >> 13) | ((green & 0x1000) >> 12)) << 4) |
16968c2ecf20Sopenharmony_ci			   ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
16978c2ecf20Sopenharmony_ci		((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) |
16988c2ecf20Sopenharmony_ci						       ((green & 0xfc00) >> 5) |
16998c2ecf20Sopenharmony_ci						       ((blue & 0xf800) >> 11));
17008c2ecf20Sopenharmony_ci	}
17018c2ecf20Sopenharmony_ci	return 0;
17028c2ecf20Sopenharmony_ci}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_cistatic int falcon_blank(int blank_mode)
17058c2ecf20Sopenharmony_ci{
17068c2ecf20Sopenharmony_ci	/* ++guenther: we can switch off graphics by changing VDB and VDE,
17078c2ecf20Sopenharmony_ci	 * so VIDEL doesn't hog the bus while saving.
17088c2ecf20Sopenharmony_ci	 * (this may affect usleep()).
17098c2ecf20Sopenharmony_ci	 */
17108c2ecf20Sopenharmony_ci	int vdb, vss, hbe, hss;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
17138c2ecf20Sopenharmony_ci		return 1;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	vdb = current_par.VDB;
17168c2ecf20Sopenharmony_ci	vss = current_par.VSS;
17178c2ecf20Sopenharmony_ci	hbe = current_par.HBE;
17188c2ecf20Sopenharmony_ci	hss = current_par.HSS;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	if (blank_mode >= 1) {
17218c2ecf20Sopenharmony_ci		/* disable graphics output (this speeds up the CPU) ... */
17228c2ecf20Sopenharmony_ci		vdb = current_par.VFT + 1;
17238c2ecf20Sopenharmony_ci		/* ... and blank all lines */
17248c2ecf20Sopenharmony_ci		hbe = current_par.HHT + 2;
17258c2ecf20Sopenharmony_ci	}
17268c2ecf20Sopenharmony_ci	/* use VESA suspend modes on VGA monitors */
17278c2ecf20Sopenharmony_ci	if (mon_type == F_MON_VGA) {
17288c2ecf20Sopenharmony_ci		if (blank_mode == 2 || blank_mode == 4)
17298c2ecf20Sopenharmony_ci			vss = current_par.VFT + 1;
17308c2ecf20Sopenharmony_ci		if (blank_mode == 3 || blank_mode == 4)
17318c2ecf20Sopenharmony_ci			hss = current_par.HHT + 2;
17328c2ecf20Sopenharmony_ci	}
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	videl.vdb = vdb;
17358c2ecf20Sopenharmony_ci	videl.vss = vss;
17368c2ecf20Sopenharmony_ci	videl.hbe = hbe;
17378c2ecf20Sopenharmony_ci	videl.hss = hss;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	return 0;
17408c2ecf20Sopenharmony_ci}
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_cistatic int falcon_detect(void)
17438c2ecf20Sopenharmony_ci{
17448c2ecf20Sopenharmony_ci	struct atafb_par par;
17458c2ecf20Sopenharmony_ci	unsigned char fhw;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	/* Determine connected monitor and set monitor parameters */
17488c2ecf20Sopenharmony_ci	fhw = *(unsigned char *)0xffff8006;
17498c2ecf20Sopenharmony_ci	mon_type = fhw >> 6 & 0x3;
17508c2ecf20Sopenharmony_ci	/* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
17518c2ecf20Sopenharmony_ci	f030_bus_width = fhw << 6 & 0x80;
17528c2ecf20Sopenharmony_ci	switch (mon_type) {
17538c2ecf20Sopenharmony_ci	case F_MON_SM:
17548c2ecf20Sopenharmony_ci		fb_info.monspecs.vfmin = 70;
17558c2ecf20Sopenharmony_ci		fb_info.monspecs.vfmax = 72;
17568c2ecf20Sopenharmony_ci		fb_info.monspecs.hfmin = 35713;
17578c2ecf20Sopenharmony_ci		fb_info.monspecs.hfmax = 35715;
17588c2ecf20Sopenharmony_ci		break;
17598c2ecf20Sopenharmony_ci	case F_MON_SC:
17608c2ecf20Sopenharmony_ci	case F_MON_TV:
17618c2ecf20Sopenharmony_ci		/* PAL...NTSC */
17628c2ecf20Sopenharmony_ci		fb_info.monspecs.vfmin = 49;	/* not 50, since TOS defaults to 49.9x Hz */
17638c2ecf20Sopenharmony_ci		fb_info.monspecs.vfmax = 60;
17648c2ecf20Sopenharmony_ci		fb_info.monspecs.hfmin = 15620;
17658c2ecf20Sopenharmony_ci		fb_info.monspecs.hfmax = 15755;
17668c2ecf20Sopenharmony_ci		break;
17678c2ecf20Sopenharmony_ci	}
17688c2ecf20Sopenharmony_ci	/* initialize hsync-len */
17698c2ecf20Sopenharmony_ci	f25.hsync = h_syncs[mon_type] / f25.t;
17708c2ecf20Sopenharmony_ci	f32.hsync = h_syncs[mon_type] / f32.t;
17718c2ecf20Sopenharmony_ci	if (fext.t)
17728c2ecf20Sopenharmony_ci		fext.hsync = h_syncs[mon_type] / fext.t;
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	falcon_get_par(&par);
17758c2ecf20Sopenharmony_ci	falcon_encode_var(&atafb_predefined[0], &par);
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	/* Detected mode is always the "autodetect" slot */
17788c2ecf20Sopenharmony_ci	return 1;
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci#endif /* ATAFB_FALCON */
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci/* ------------------- ST(E) specific functions ---------------------- */
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci#ifdef ATAFB_STE
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_cistatic int stste_encode_fix(struct fb_fix_screeninfo *fix,
17888c2ecf20Sopenharmony_ci			    struct atafb_par *par)
17898c2ecf20Sopenharmony_ci{
17908c2ecf20Sopenharmony_ci	int mode;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	strcpy(fix->id, "Atari Builtin");
17938c2ecf20Sopenharmony_ci	fix->smem_start = phys_screen_base;
17948c2ecf20Sopenharmony_ci	fix->smem_len = screen_len;
17958c2ecf20Sopenharmony_ci	fix->type = FB_TYPE_INTERLEAVED_PLANES;
17968c2ecf20Sopenharmony_ci	fix->type_aux = 2;
17978c2ecf20Sopenharmony_ci	fix->visual = FB_VISUAL_PSEUDOCOLOR;
17988c2ecf20Sopenharmony_ci	mode = par->hw.st.mode & 3;
17998c2ecf20Sopenharmony_ci	if (mode == ST_HIGH) {
18008c2ecf20Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
18018c2ecf20Sopenharmony_ci		fix->type_aux = 0;
18028c2ecf20Sopenharmony_ci		fix->visual = FB_VISUAL_MONO10;
18038c2ecf20Sopenharmony_ci	}
18048c2ecf20Sopenharmony_ci	if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
18058c2ecf20Sopenharmony_ci		fix->xpanstep = 16;
18068c2ecf20Sopenharmony_ci		fix->ypanstep = 1;
18078c2ecf20Sopenharmony_ci	} else {
18088c2ecf20Sopenharmony_ci		fix->xpanstep = 0;
18098c2ecf20Sopenharmony_ci		fix->ypanstep = 0;
18108c2ecf20Sopenharmony_ci	}
18118c2ecf20Sopenharmony_ci	fix->ywrapstep = 0;
18128c2ecf20Sopenharmony_ci	fix->line_length = par->next_line;
18138c2ecf20Sopenharmony_ci	fix->accel = FB_ACCEL_ATARIBLITT;
18148c2ecf20Sopenharmony_ci	return 0;
18158c2ecf20Sopenharmony_ci}
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_cistatic int stste_decode_var(struct fb_var_screeninfo *var,
18188c2ecf20Sopenharmony_ci			    struct atafb_par *par)
18198c2ecf20Sopenharmony_ci{
18208c2ecf20Sopenharmony_ci	int xres = var->xres;
18218c2ecf20Sopenharmony_ci	int yres = var->yres;
18228c2ecf20Sopenharmony_ci	int bpp = var->bits_per_pixel;
18238c2ecf20Sopenharmony_ci	int linelen;
18248c2ecf20Sopenharmony_ci	int yres_virtual = var->yres_virtual;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	if (mono_moni) {
18278c2ecf20Sopenharmony_ci		if (bpp > 1 || xres > sttt_xres || yres > st_yres)
18288c2ecf20Sopenharmony_ci			return -EINVAL;
18298c2ecf20Sopenharmony_ci		par->hw.st.mode = ST_HIGH;
18308c2ecf20Sopenharmony_ci		xres = sttt_xres;
18318c2ecf20Sopenharmony_ci		yres = st_yres;
18328c2ecf20Sopenharmony_ci		bpp = 1;
18338c2ecf20Sopenharmony_ci	} else {
18348c2ecf20Sopenharmony_ci		if (bpp > 4 || xres > sttt_xres || yres > st_yres)
18358c2ecf20Sopenharmony_ci			return -EINVAL;
18368c2ecf20Sopenharmony_ci		if (bpp > 2) {
18378c2ecf20Sopenharmony_ci			if (xres > sttt_xres / 2 || yres > st_yres / 2)
18388c2ecf20Sopenharmony_ci				return -EINVAL;
18398c2ecf20Sopenharmony_ci			par->hw.st.mode = ST_LOW;
18408c2ecf20Sopenharmony_ci			xres = sttt_xres / 2;
18418c2ecf20Sopenharmony_ci			yres = st_yres / 2;
18428c2ecf20Sopenharmony_ci			bpp = 4;
18438c2ecf20Sopenharmony_ci		} else if (bpp > 1) {
18448c2ecf20Sopenharmony_ci			if (xres > sttt_xres || yres > st_yres / 2)
18458c2ecf20Sopenharmony_ci				return -EINVAL;
18468c2ecf20Sopenharmony_ci			par->hw.st.mode = ST_MID;
18478c2ecf20Sopenharmony_ci			xres = sttt_xres;
18488c2ecf20Sopenharmony_ci			yres = st_yres / 2;
18498c2ecf20Sopenharmony_ci			bpp = 2;
18508c2ecf20Sopenharmony_ci		} else
18518c2ecf20Sopenharmony_ci			return -EINVAL;
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci	if (yres_virtual <= 0)
18548c2ecf20Sopenharmony_ci		yres_virtual = 0;
18558c2ecf20Sopenharmony_ci	else if (yres_virtual < yres)
18568c2ecf20Sopenharmony_ci		yres_virtual = yres;
18578c2ecf20Sopenharmony_ci	if (var->sync & FB_SYNC_EXT)
18588c2ecf20Sopenharmony_ci		par->hw.st.sync = (par->hw.st.sync & ~1) | 1;
18598c2ecf20Sopenharmony_ci	else
18608c2ecf20Sopenharmony_ci		par->hw.st.sync = (par->hw.st.sync & ~1);
18618c2ecf20Sopenharmony_ci	linelen = xres * bpp / 8;
18628c2ecf20Sopenharmony_ci	if (yres_virtual * linelen > screen_len && screen_len)
18638c2ecf20Sopenharmony_ci		return -EINVAL;
18648c2ecf20Sopenharmony_ci	if (yres * linelen > screen_len && screen_len)
18658c2ecf20Sopenharmony_ci		return -EINVAL;
18668c2ecf20Sopenharmony_ci	if (var->yoffset + yres > yres_virtual && yres_virtual)
18678c2ecf20Sopenharmony_ci		return -EINVAL;
18688c2ecf20Sopenharmony_ci	par->yres_virtual = yres_virtual;
18698c2ecf20Sopenharmony_ci	par->screen_base = screen_base + var->yoffset * linelen;
18708c2ecf20Sopenharmony_ci	par->next_line = linelen;
18718c2ecf20Sopenharmony_ci	return 0;
18728c2ecf20Sopenharmony_ci}
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_cistatic int stste_encode_var(struct fb_var_screeninfo *var,
18758c2ecf20Sopenharmony_ci			    struct atafb_par *par)
18768c2ecf20Sopenharmony_ci{
18778c2ecf20Sopenharmony_ci	int linelen;
18788c2ecf20Sopenharmony_ci	memset(var, 0, sizeof(struct fb_var_screeninfo));
18798c2ecf20Sopenharmony_ci	var->red.offset = 0;
18808c2ecf20Sopenharmony_ci	var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
18818c2ecf20Sopenharmony_ci	var->red.msb_right = 0;
18828c2ecf20Sopenharmony_ci	var->grayscale = 0;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	var->pixclock = 31041;
18858c2ecf20Sopenharmony_ci	var->left_margin = 120;		/* these are incorrect */
18868c2ecf20Sopenharmony_ci	var->right_margin = 100;
18878c2ecf20Sopenharmony_ci	var->upper_margin = 8;
18888c2ecf20Sopenharmony_ci	var->lower_margin = 16;
18898c2ecf20Sopenharmony_ci	var->hsync_len = 140;
18908c2ecf20Sopenharmony_ci	var->vsync_len = 30;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	var->height = -1;
18938c2ecf20Sopenharmony_ci	var->width = -1;
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if (!(par->hw.st.sync & 1))
18968c2ecf20Sopenharmony_ci		var->sync = 0;
18978c2ecf20Sopenharmony_ci	else
18988c2ecf20Sopenharmony_ci		var->sync = FB_SYNC_EXT;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	switch (par->hw.st.mode & 3) {
19018c2ecf20Sopenharmony_ci	case ST_LOW:
19028c2ecf20Sopenharmony_ci		var->xres = sttt_xres / 2;
19038c2ecf20Sopenharmony_ci		var->yres = st_yres / 2;
19048c2ecf20Sopenharmony_ci		var->bits_per_pixel = 4;
19058c2ecf20Sopenharmony_ci		break;
19068c2ecf20Sopenharmony_ci	case ST_MID:
19078c2ecf20Sopenharmony_ci		var->xres = sttt_xres;
19088c2ecf20Sopenharmony_ci		var->yres = st_yres / 2;
19098c2ecf20Sopenharmony_ci		var->bits_per_pixel = 2;
19108c2ecf20Sopenharmony_ci		break;
19118c2ecf20Sopenharmony_ci	case ST_HIGH:
19128c2ecf20Sopenharmony_ci		var->xres = sttt_xres;
19138c2ecf20Sopenharmony_ci		var->yres = st_yres;
19148c2ecf20Sopenharmony_ci		var->bits_per_pixel = 1;
19158c2ecf20Sopenharmony_ci		break;
19168c2ecf20Sopenharmony_ci	}
19178c2ecf20Sopenharmony_ci	var->blue = var->green = var->red;
19188c2ecf20Sopenharmony_ci	var->transp.offset = 0;
19198c2ecf20Sopenharmony_ci	var->transp.length = 0;
19208c2ecf20Sopenharmony_ci	var->transp.msb_right = 0;
19218c2ecf20Sopenharmony_ci	var->xres_virtual = sttt_xres_virtual;
19228c2ecf20Sopenharmony_ci	linelen = var->xres_virtual * var->bits_per_pixel / 8;
19238c2ecf20Sopenharmony_ci	ovsc_addlen = linelen * (sttt_yres_virtual - st_yres);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	if (!use_hwscroll)
19268c2ecf20Sopenharmony_ci		var->yres_virtual = var->yres;
19278c2ecf20Sopenharmony_ci	else if (screen_len) {
19288c2ecf20Sopenharmony_ci		if (par->yres_virtual)
19298c2ecf20Sopenharmony_ci			var->yres_virtual = par->yres_virtual;
19308c2ecf20Sopenharmony_ci		else
19318c2ecf20Sopenharmony_ci			/* yres_virtual == 0 means use maximum */
19328c2ecf20Sopenharmony_ci			var->yres_virtual = screen_len / linelen;
19338c2ecf20Sopenharmony_ci	} else {
19348c2ecf20Sopenharmony_ci		if (hwscroll < 0)
19358c2ecf20Sopenharmony_ci			var->yres_virtual = 2 * var->yres;
19368c2ecf20Sopenharmony_ci		else
19378c2ecf20Sopenharmony_ci			var->yres_virtual = var->yres + hwscroll * 16;
19388c2ecf20Sopenharmony_ci	}
19398c2ecf20Sopenharmony_ci	var->xoffset = 0;
19408c2ecf20Sopenharmony_ci	if (screen_base)
19418c2ecf20Sopenharmony_ci		var->yoffset = (par->screen_base - screen_base) / linelen;
19428c2ecf20Sopenharmony_ci	else
19438c2ecf20Sopenharmony_ci		var->yoffset = 0;
19448c2ecf20Sopenharmony_ci	var->nonstd = 0;
19458c2ecf20Sopenharmony_ci	var->activate = 0;
19468c2ecf20Sopenharmony_ci	var->vmode = FB_VMODE_NONINTERLACED;
19478c2ecf20Sopenharmony_ci	return 0;
19488c2ecf20Sopenharmony_ci}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_cistatic void stste_get_par(struct atafb_par *par)
19518c2ecf20Sopenharmony_ci{
19528c2ecf20Sopenharmony_ci	unsigned long addr;
19538c2ecf20Sopenharmony_ci	par->hw.st.mode = shifter_tt.st_shiftmode;
19548c2ecf20Sopenharmony_ci	par->hw.st.sync = shifter_st.syncmode;
19558c2ecf20Sopenharmony_ci	addr = ((shifter_st.bas_hi & 0xff) << 16) |
19568c2ecf20Sopenharmony_ci	       ((shifter_st.bas_md & 0xff) << 8);
19578c2ecf20Sopenharmony_ci	if (ATARIHW_PRESENT(EXTD_SHIFTER))
19588c2ecf20Sopenharmony_ci		addr |= (shifter_st.bas_lo & 0xff);
19598c2ecf20Sopenharmony_ci	par->screen_base = atari_stram_to_virt(addr);
19608c2ecf20Sopenharmony_ci}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_cistatic void stste_set_par(struct atafb_par *par)
19638c2ecf20Sopenharmony_ci{
19648c2ecf20Sopenharmony_ci	shifter_tt.st_shiftmode = par->hw.st.mode;
19658c2ecf20Sopenharmony_ci	shifter_st.syncmode = par->hw.st.sync;
19668c2ecf20Sopenharmony_ci	/* only set screen_base if really necessary */
19678c2ecf20Sopenharmony_ci	if (current_par.screen_base != par->screen_base)
19688c2ecf20Sopenharmony_ci		fbhw->set_screen_base(par->screen_base);
19698c2ecf20Sopenharmony_ci}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_cistatic int stste_setcolreg(unsigned int regno, unsigned int red,
19728c2ecf20Sopenharmony_ci			   unsigned int green, unsigned int blue,
19738c2ecf20Sopenharmony_ci			   unsigned int transp, struct fb_info *info)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	if (regno > 15)
19768c2ecf20Sopenharmony_ci		return 1;
19778c2ecf20Sopenharmony_ci	red >>= 12;
19788c2ecf20Sopenharmony_ci	blue >>= 12;
19798c2ecf20Sopenharmony_ci	green >>= 12;
19808c2ecf20Sopenharmony_ci	if (ATARIHW_PRESENT(EXTD_SHIFTER))
19818c2ecf20Sopenharmony_ci		shifter_tt.color_reg[regno] =
19828c2ecf20Sopenharmony_ci			((((red & 0xe)   >> 1) | ((red & 1)   << 3)) << 8) |
19838c2ecf20Sopenharmony_ci			((((green & 0xe) >> 1) | ((green & 1) << 3)) << 4) |
19848c2ecf20Sopenharmony_ci			  ((blue & 0xe)  >> 1) | ((blue & 1)  << 3);
19858c2ecf20Sopenharmony_ci	else
19868c2ecf20Sopenharmony_ci		shifter_tt.color_reg[regno] =
19878c2ecf20Sopenharmony_ci			((red & 0xe) << 7) |
19888c2ecf20Sopenharmony_ci			((green & 0xe) << 3) |
19898c2ecf20Sopenharmony_ci			((blue & 0xe) >> 1);
19908c2ecf20Sopenharmony_ci	return 0;
19918c2ecf20Sopenharmony_ci}
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_cistatic int stste_detect(void)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	struct atafb_par par;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci	/* Determine the connected monitor: The DMA sound must be
19988c2ecf20Sopenharmony_ci	 * disabled before reading the MFP GPIP, because the Sound
19998c2ecf20Sopenharmony_ci	 * Done Signal and the Monochrome Detect are XORed together!
20008c2ecf20Sopenharmony_ci	 */
20018c2ecf20Sopenharmony_ci	if (ATARIHW_PRESENT(PCM_8BIT)) {
20028c2ecf20Sopenharmony_ci		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
20038c2ecf20Sopenharmony_ci		udelay(20);		/* wait a while for things to settle down */
20048c2ecf20Sopenharmony_ci	}
20058c2ecf20Sopenharmony_ci	mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci	stste_get_par(&par);
20088c2ecf20Sopenharmony_ci	stste_encode_var(&atafb_predefined[0], &par);
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	if (!ATARIHW_PRESENT(EXTD_SHIFTER))
20118c2ecf20Sopenharmony_ci		use_hwscroll = 0;
20128c2ecf20Sopenharmony_ci	return 1;
20138c2ecf20Sopenharmony_ci}
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_cistatic void stste_set_screen_base(void *s_base)
20168c2ecf20Sopenharmony_ci{
20178c2ecf20Sopenharmony_ci	unsigned long addr;
20188c2ecf20Sopenharmony_ci	addr = atari_stram_to_phys(s_base);
20198c2ecf20Sopenharmony_ci	/* Setup Screen Memory */
20208c2ecf20Sopenharmony_ci	shifter_st.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
20218c2ecf20Sopenharmony_ci	shifter_st.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
20228c2ecf20Sopenharmony_ci	if (ATARIHW_PRESENT(EXTD_SHIFTER))
20238c2ecf20Sopenharmony_ci		shifter_st.bas_lo = (unsigned char)(addr & 0x0000ff);
20248c2ecf20Sopenharmony_ci}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci#endif /* ATAFB_STE */
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci/* Switching the screen size should be done during vsync, otherwise
20298c2ecf20Sopenharmony_ci * the margins may get messed up. This is a well known problem of
20308c2ecf20Sopenharmony_ci * the ST's video system.
20318c2ecf20Sopenharmony_ci *
20328c2ecf20Sopenharmony_ci * Unfortunately there is hardly any way to find the vsync, as the
20338c2ecf20Sopenharmony_ci * vertical blank interrupt is no longer in time on machines with
20348c2ecf20Sopenharmony_ci * overscan type modifications.
20358c2ecf20Sopenharmony_ci *
20368c2ecf20Sopenharmony_ci * We can, however, use Timer B to safely detect the black shoulder,
20378c2ecf20Sopenharmony_ci * but then we've got to guess an appropriate delay to find the vsync.
20388c2ecf20Sopenharmony_ci * This might not work on every machine.
20398c2ecf20Sopenharmony_ci *
20408c2ecf20Sopenharmony_ci * martin_rogge @ ki.maus.de, 8th Aug 1995
20418c2ecf20Sopenharmony_ci */
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci#define LINE_DELAY  (mono_moni ? 30 : 70)
20448c2ecf20Sopenharmony_ci#define SYNC_DELAY  (mono_moni ? 1500 : 2000)
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
20478c2ecf20Sopenharmony_cistatic void st_ovsc_switch(void)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	unsigned long flags;
20508c2ecf20Sopenharmony_ci	register unsigned char old, new;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
20538c2ecf20Sopenharmony_ci		return;
20548c2ecf20Sopenharmony_ci	local_irq_save(flags);
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	st_mfp.tim_ct_b = 0x10;
20578c2ecf20Sopenharmony_ci	st_mfp.active_edge |= 8;
20588c2ecf20Sopenharmony_ci	st_mfp.tim_ct_b = 0;
20598c2ecf20Sopenharmony_ci	st_mfp.tim_dt_b = 0xf0;
20608c2ecf20Sopenharmony_ci	st_mfp.tim_ct_b = 8;
20618c2ecf20Sopenharmony_ci	while (st_mfp.tim_dt_b > 1)	/* TOS does it this way, don't ask why */
20628c2ecf20Sopenharmony_ci		;
20638c2ecf20Sopenharmony_ci	new = st_mfp.tim_dt_b;
20648c2ecf20Sopenharmony_ci	do {
20658c2ecf20Sopenharmony_ci		udelay(LINE_DELAY);
20668c2ecf20Sopenharmony_ci		old = new;
20678c2ecf20Sopenharmony_ci		new = st_mfp.tim_dt_b;
20688c2ecf20Sopenharmony_ci	} while (old != new);
20698c2ecf20Sopenharmony_ci	st_mfp.tim_ct_b = 0x10;
20708c2ecf20Sopenharmony_ci	udelay(SYNC_DELAY);
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
20738c2ecf20Sopenharmony_ci		acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
20748c2ecf20Sopenharmony_ci	if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
20758c2ecf20Sopenharmony_ci		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
20768c2ecf20Sopenharmony_ci	if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
20778c2ecf20Sopenharmony_ci		sound_ym.rd_data_reg_sel = 14;
20788c2ecf20Sopenharmony_ci		sound_ym.wd_data = sound_ym.rd_data_reg_sel |
20798c2ecf20Sopenharmony_ci				   ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
20808c2ecf20Sopenharmony_ci				   ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
20818c2ecf20Sopenharmony_ci	}
20828c2ecf20Sopenharmony_ci	local_irq_restore(flags);
20838c2ecf20Sopenharmony_ci}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci/* ------------------- External Video ---------------------- */
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_cistatic int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	strcpy(fix->id, "Unknown Extern");
20928c2ecf20Sopenharmony_ci	fix->smem_start = external_addr;
20938c2ecf20Sopenharmony_ci	fix->smem_len = PAGE_ALIGN(external_len);
20948c2ecf20Sopenharmony_ci	if (external_depth == 1) {
20958c2ecf20Sopenharmony_ci		fix->type = FB_TYPE_PACKED_PIXELS;
20968c2ecf20Sopenharmony_ci		/* The letters 'n' and 'i' in the "atavideo=external:" stand
20978c2ecf20Sopenharmony_ci		 * for "normal" and "inverted", rsp., in the monochrome case */
20988c2ecf20Sopenharmony_ci		fix->visual =
20998c2ecf20Sopenharmony_ci			(external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
21008c2ecf20Sopenharmony_ci			 external_pmode == FB_TYPE_PACKED_PIXELS) ?
21018c2ecf20Sopenharmony_ci				FB_VISUAL_MONO10 : FB_VISUAL_MONO01;
21028c2ecf20Sopenharmony_ci	} else {
21038c2ecf20Sopenharmony_ci		/* Use STATIC if we don't know how to access color registers */
21048c2ecf20Sopenharmony_ci		int visual = external_vgaiobase ?
21058c2ecf20Sopenharmony_ci					 FB_VISUAL_PSEUDOCOLOR :
21068c2ecf20Sopenharmony_ci					 FB_VISUAL_STATIC_PSEUDOCOLOR;
21078c2ecf20Sopenharmony_ci		switch (external_pmode) {
21088c2ecf20Sopenharmony_ci		case -1:		/* truecolor */
21098c2ecf20Sopenharmony_ci			fix->type = FB_TYPE_PACKED_PIXELS;
21108c2ecf20Sopenharmony_ci			fix->visual = FB_VISUAL_TRUECOLOR;
21118c2ecf20Sopenharmony_ci			break;
21128c2ecf20Sopenharmony_ci		case FB_TYPE_PACKED_PIXELS:
21138c2ecf20Sopenharmony_ci			fix->type = FB_TYPE_PACKED_PIXELS;
21148c2ecf20Sopenharmony_ci			fix->visual = visual;
21158c2ecf20Sopenharmony_ci			break;
21168c2ecf20Sopenharmony_ci		case FB_TYPE_PLANES:
21178c2ecf20Sopenharmony_ci			fix->type = FB_TYPE_PLANES;
21188c2ecf20Sopenharmony_ci			fix->visual = visual;
21198c2ecf20Sopenharmony_ci			break;
21208c2ecf20Sopenharmony_ci		case FB_TYPE_INTERLEAVED_PLANES:
21218c2ecf20Sopenharmony_ci			fix->type = FB_TYPE_INTERLEAVED_PLANES;
21228c2ecf20Sopenharmony_ci			fix->type_aux = 2;
21238c2ecf20Sopenharmony_ci			fix->visual = visual;
21248c2ecf20Sopenharmony_ci			break;
21258c2ecf20Sopenharmony_ci		}
21268c2ecf20Sopenharmony_ci	}
21278c2ecf20Sopenharmony_ci	fix->xpanstep = 0;
21288c2ecf20Sopenharmony_ci	fix->ypanstep = 0;
21298c2ecf20Sopenharmony_ci	fix->ywrapstep = 0;
21308c2ecf20Sopenharmony_ci	fix->line_length = par->next_line;
21318c2ecf20Sopenharmony_ci	return 0;
21328c2ecf20Sopenharmony_ci}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_cistatic int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
21358c2ecf20Sopenharmony_ci{
21368c2ecf20Sopenharmony_ci	struct fb_var_screeninfo *myvar = &atafb_predefined[0];
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	if (var->bits_per_pixel > myvar->bits_per_pixel ||
21398c2ecf20Sopenharmony_ci	    var->xres > myvar->xres ||
21408c2ecf20Sopenharmony_ci	    var->xres_virtual > myvar->xres_virtual ||
21418c2ecf20Sopenharmony_ci	    var->yres > myvar->yres ||
21428c2ecf20Sopenharmony_ci	    var->xoffset > 0 ||
21438c2ecf20Sopenharmony_ci	    var->yoffset > 0)
21448c2ecf20Sopenharmony_ci		return -EINVAL;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci	par->next_line = external_xres_virtual * external_depth / 8;
21478c2ecf20Sopenharmony_ci	return 0;
21488c2ecf20Sopenharmony_ci}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_cistatic int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
21518c2ecf20Sopenharmony_ci{
21528c2ecf20Sopenharmony_ci	memset(var, 0, sizeof(struct fb_var_screeninfo));
21538c2ecf20Sopenharmony_ci	var->red.offset = 0;
21548c2ecf20Sopenharmony_ci	var->red.length = (external_pmode == -1) ? external_depth / 3 :
21558c2ecf20Sopenharmony_ci			(external_vgaiobase ? external_bitspercol : 0);
21568c2ecf20Sopenharmony_ci	var->red.msb_right = 0;
21578c2ecf20Sopenharmony_ci	var->grayscale = 0;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	var->pixclock = 31041;
21608c2ecf20Sopenharmony_ci	var->left_margin = 120;		/* these are surely incorrect */
21618c2ecf20Sopenharmony_ci	var->right_margin = 100;
21628c2ecf20Sopenharmony_ci	var->upper_margin = 8;
21638c2ecf20Sopenharmony_ci	var->lower_margin = 16;
21648c2ecf20Sopenharmony_ci	var->hsync_len = 140;
21658c2ecf20Sopenharmony_ci	var->vsync_len = 30;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	var->height = -1;
21688c2ecf20Sopenharmony_ci	var->width = -1;
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	var->sync = 0;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	var->xres = external_xres;
21738c2ecf20Sopenharmony_ci	var->yres = external_yres;
21748c2ecf20Sopenharmony_ci	var->xres_virtual = external_xres_virtual;
21758c2ecf20Sopenharmony_ci	var->bits_per_pixel = external_depth;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	var->blue = var->green = var->red;
21788c2ecf20Sopenharmony_ci	var->transp.offset = 0;
21798c2ecf20Sopenharmony_ci	var->transp.length = 0;
21808c2ecf20Sopenharmony_ci	var->transp.msb_right = 0;
21818c2ecf20Sopenharmony_ci	var->yres_virtual = var->yres;
21828c2ecf20Sopenharmony_ci	var->xoffset = 0;
21838c2ecf20Sopenharmony_ci	var->yoffset = 0;
21848c2ecf20Sopenharmony_ci	var->nonstd = 0;
21858c2ecf20Sopenharmony_ci	var->activate = 0;
21868c2ecf20Sopenharmony_ci	var->vmode = FB_VMODE_NONINTERLACED;
21878c2ecf20Sopenharmony_ci	return 0;
21888c2ecf20Sopenharmony_ci}
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_cistatic void ext_get_par(struct atafb_par *par)
21918c2ecf20Sopenharmony_ci{
21928c2ecf20Sopenharmony_ci	par->screen_base = external_screen_base;
21938c2ecf20Sopenharmony_ci}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_cistatic void ext_set_par(struct atafb_par *par)
21968c2ecf20Sopenharmony_ci{
21978c2ecf20Sopenharmony_ci}
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci#define OUTB(port,val) \
22008c2ecf20Sopenharmony_ci	*((unsigned volatile char *) ((port)+external_vgaiobase)) = (val)
22018c2ecf20Sopenharmony_ci#define INB(port) \
22028c2ecf20Sopenharmony_ci	(*((unsigned volatile char *) ((port)+external_vgaiobase)))
22038c2ecf20Sopenharmony_ci#define DACDelay				\
22048c2ecf20Sopenharmony_ci	do {					\
22058c2ecf20Sopenharmony_ci		unsigned char tmp = INB(0x3da);	\
22068c2ecf20Sopenharmony_ci		tmp = INB(0x3da);			\
22078c2ecf20Sopenharmony_ci	} while (0)
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_cistatic int ext_setcolreg(unsigned int regno, unsigned int red,
22108c2ecf20Sopenharmony_ci			 unsigned int green, unsigned int blue,
22118c2ecf20Sopenharmony_ci			 unsigned int transp, struct fb_info *info)
22128c2ecf20Sopenharmony_ci{
22138c2ecf20Sopenharmony_ci	unsigned char colmask = (1 << external_bitspercol) - 1;
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	if (!external_vgaiobase)
22168c2ecf20Sopenharmony_ci		return 1;
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ci	if (regno > 255)
22198c2ecf20Sopenharmony_ci		return 1;
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	switch (external_card_type) {
22228c2ecf20Sopenharmony_ci	case IS_VGA:
22238c2ecf20Sopenharmony_ci		OUTB(0x3c8, regno);
22248c2ecf20Sopenharmony_ci		DACDelay;
22258c2ecf20Sopenharmony_ci		OUTB(0x3c9, red & colmask);
22268c2ecf20Sopenharmony_ci		DACDelay;
22278c2ecf20Sopenharmony_ci		OUTB(0x3c9, green & colmask);
22288c2ecf20Sopenharmony_ci		DACDelay;
22298c2ecf20Sopenharmony_ci		OUTB(0x3c9, blue & colmask);
22308c2ecf20Sopenharmony_ci		DACDelay;
22318c2ecf20Sopenharmony_ci		return 0;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	case IS_MV300:
22348c2ecf20Sopenharmony_ci		OUTB((MV300_reg[regno] << 2) + 1, red);
22358c2ecf20Sopenharmony_ci		OUTB((MV300_reg[regno] << 2) + 1, green);
22368c2ecf20Sopenharmony_ci		OUTB((MV300_reg[regno] << 2) + 1, blue);
22378c2ecf20Sopenharmony_ci		return 0;
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	default:
22408c2ecf20Sopenharmony_ci		return 1;
22418c2ecf20Sopenharmony_ci	}
22428c2ecf20Sopenharmony_ci}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_cistatic int ext_detect(void)
22458c2ecf20Sopenharmony_ci{
22468c2ecf20Sopenharmony_ci	struct fb_var_screeninfo *myvar = &atafb_predefined[0];
22478c2ecf20Sopenharmony_ci	struct atafb_par dummy_par;
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci	myvar->xres = external_xres;
22508c2ecf20Sopenharmony_ci	myvar->xres_virtual = external_xres_virtual;
22518c2ecf20Sopenharmony_ci	myvar->yres = external_yres;
22528c2ecf20Sopenharmony_ci	myvar->bits_per_pixel = external_depth;
22538c2ecf20Sopenharmony_ci	ext_encode_var(myvar, &dummy_par);
22548c2ecf20Sopenharmony_ci	return 1;
22558c2ecf20Sopenharmony_ci}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci#endif /* ATAFB_EXT */
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci/* ------ This is the same for most hardware types -------- */
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_cistatic void set_screen_base(void *s_base)
22628c2ecf20Sopenharmony_ci{
22638c2ecf20Sopenharmony_ci	unsigned long addr;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	addr = atari_stram_to_phys(s_base);
22668c2ecf20Sopenharmony_ci	/* Setup Screen Memory */
22678c2ecf20Sopenharmony_ci	shifter_st.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
22688c2ecf20Sopenharmony_ci	shifter_st.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
22698c2ecf20Sopenharmony_ci	shifter_st.bas_lo = (unsigned char)(addr & 0x0000ff);
22708c2ecf20Sopenharmony_ci}
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_cistatic int pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
22738c2ecf20Sopenharmony_ci{
22748c2ecf20Sopenharmony_ci	struct atafb_par *par = (struct atafb_par *)info->par;
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	if (!fbhw->set_screen_base ||
22778c2ecf20Sopenharmony_ci	    (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
22788c2ecf20Sopenharmony_ci		return -EINVAL;
22798c2ecf20Sopenharmony_ci	var->xoffset = up(var->xoffset, 16);
22808c2ecf20Sopenharmony_ci	par->screen_base = screen_base +
22818c2ecf20Sopenharmony_ci	        (var->yoffset * info->var.xres_virtual + var->xoffset)
22828c2ecf20Sopenharmony_ci	        * info->var.bits_per_pixel / 8;
22838c2ecf20Sopenharmony_ci	fbhw->set_screen_base(par->screen_base);
22848c2ecf20Sopenharmony_ci	return 0;
22858c2ecf20Sopenharmony_ci}
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci/* ------------ Interfaces to hardware functions ------------ */
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci#ifdef ATAFB_TT
22908c2ecf20Sopenharmony_cistatic struct fb_hwswitch tt_switch = {
22918c2ecf20Sopenharmony_ci	.detect		= tt_detect,
22928c2ecf20Sopenharmony_ci	.encode_fix	= tt_encode_fix,
22938c2ecf20Sopenharmony_ci	.decode_var	= tt_decode_var,
22948c2ecf20Sopenharmony_ci	.encode_var	= tt_encode_var,
22958c2ecf20Sopenharmony_ci	.get_par	= tt_get_par,
22968c2ecf20Sopenharmony_ci	.set_par	= tt_set_par,
22978c2ecf20Sopenharmony_ci	.set_screen_base = set_screen_base,
22988c2ecf20Sopenharmony_ci	.pan_display	= pan_display,
22998c2ecf20Sopenharmony_ci};
23008c2ecf20Sopenharmony_ci#endif
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
23038c2ecf20Sopenharmony_cistatic struct fb_hwswitch falcon_switch = {
23048c2ecf20Sopenharmony_ci	.detect		= falcon_detect,
23058c2ecf20Sopenharmony_ci	.encode_fix	= falcon_encode_fix,
23068c2ecf20Sopenharmony_ci	.decode_var	= falcon_decode_var,
23078c2ecf20Sopenharmony_ci	.encode_var	= falcon_encode_var,
23088c2ecf20Sopenharmony_ci	.get_par	= falcon_get_par,
23098c2ecf20Sopenharmony_ci	.set_par	= falcon_set_par,
23108c2ecf20Sopenharmony_ci	.set_screen_base = set_screen_base,
23118c2ecf20Sopenharmony_ci	.blank		= falcon_blank,
23128c2ecf20Sopenharmony_ci	.pan_display	= falcon_pan_display,
23138c2ecf20Sopenharmony_ci};
23148c2ecf20Sopenharmony_ci#endif
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci#ifdef ATAFB_STE
23178c2ecf20Sopenharmony_cistatic struct fb_hwswitch st_switch = {
23188c2ecf20Sopenharmony_ci	.detect		= stste_detect,
23198c2ecf20Sopenharmony_ci	.encode_fix	= stste_encode_fix,
23208c2ecf20Sopenharmony_ci	.decode_var	= stste_decode_var,
23218c2ecf20Sopenharmony_ci	.encode_var	= stste_encode_var,
23228c2ecf20Sopenharmony_ci	.get_par	= stste_get_par,
23238c2ecf20Sopenharmony_ci	.set_par	= stste_set_par,
23248c2ecf20Sopenharmony_ci	.set_screen_base = stste_set_screen_base,
23258c2ecf20Sopenharmony_ci	.pan_display	= pan_display
23268c2ecf20Sopenharmony_ci};
23278c2ecf20Sopenharmony_ci#endif
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
23308c2ecf20Sopenharmony_cistatic struct fb_hwswitch ext_switch = {
23318c2ecf20Sopenharmony_ci	.detect		= ext_detect,
23328c2ecf20Sopenharmony_ci	.encode_fix	= ext_encode_fix,
23338c2ecf20Sopenharmony_ci	.decode_var	= ext_decode_var,
23348c2ecf20Sopenharmony_ci	.encode_var	= ext_encode_var,
23358c2ecf20Sopenharmony_ci	.get_par	= ext_get_par,
23368c2ecf20Sopenharmony_ci	.set_par	= ext_set_par,
23378c2ecf20Sopenharmony_ci};
23388c2ecf20Sopenharmony_ci#endif
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_cistatic void ata_get_par(struct atafb_par *par)
23418c2ecf20Sopenharmony_ci{
23428c2ecf20Sopenharmony_ci	if (current_par_valid)
23438c2ecf20Sopenharmony_ci		*par = current_par;
23448c2ecf20Sopenharmony_ci	else
23458c2ecf20Sopenharmony_ci		fbhw->get_par(par);
23468c2ecf20Sopenharmony_ci}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_cistatic void ata_set_par(struct atafb_par *par)
23498c2ecf20Sopenharmony_ci{
23508c2ecf20Sopenharmony_ci	fbhw->set_par(par);
23518c2ecf20Sopenharmony_ci	current_par = *par;
23528c2ecf20Sopenharmony_ci	current_par_valid = 1;
23538c2ecf20Sopenharmony_ci}
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci/* =========================================================== */
23578c2ecf20Sopenharmony_ci/* ============== Hardware Independent Functions ============= */
23588c2ecf20Sopenharmony_ci/* =========================================================== */
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci/* used for hardware scrolling */
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_cistatic int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
23638c2ecf20Sopenharmony_ci{
23648c2ecf20Sopenharmony_ci	int err, activate;
23658c2ecf20Sopenharmony_ci	struct atafb_par par;
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	err = fbhw->decode_var(var, &par);
23688c2ecf20Sopenharmony_ci	if (err)
23698c2ecf20Sopenharmony_ci		return err;
23708c2ecf20Sopenharmony_ci	activate = var->activate;
23718c2ecf20Sopenharmony_ci	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
23728c2ecf20Sopenharmony_ci		ata_set_par(&par);
23738c2ecf20Sopenharmony_ci	fbhw->encode_var(var, &par);
23748c2ecf20Sopenharmony_ci	var->activate = activate;
23758c2ecf20Sopenharmony_ci	return 0;
23768c2ecf20Sopenharmony_ci}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci/* fbhw->encode_fix() must be called with fb_info->mm_lock held
23798c2ecf20Sopenharmony_ci * if it is called after the register_framebuffer() - not a case here
23808c2ecf20Sopenharmony_ci */
23818c2ecf20Sopenharmony_cistatic int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
23828c2ecf20Sopenharmony_ci{
23838c2ecf20Sopenharmony_ci	struct atafb_par par;
23848c2ecf20Sopenharmony_ci	int err;
23858c2ecf20Sopenharmony_ci	// Get fix directly (case con == -1 before)??
23868c2ecf20Sopenharmony_ci	err = fbhw->decode_var(&info->var, &par);
23878c2ecf20Sopenharmony_ci	if (err)
23888c2ecf20Sopenharmony_ci		return err;
23898c2ecf20Sopenharmony_ci	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
23908c2ecf20Sopenharmony_ci	err = fbhw->encode_fix(fix, &par);
23918c2ecf20Sopenharmony_ci	return err;
23928c2ecf20Sopenharmony_ci}
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_cistatic int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
23958c2ecf20Sopenharmony_ci{
23968c2ecf20Sopenharmony_ci	struct atafb_par par;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	ata_get_par(&par);
23998c2ecf20Sopenharmony_ci	fbhw->encode_var(var, &par);
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	return 0;
24028c2ecf20Sopenharmony_ci}
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci// No longer called by fbcon!
24058c2ecf20Sopenharmony_ci// Still called by set_var internally
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_cistatic void atafb_set_disp(struct fb_info *info)
24088c2ecf20Sopenharmony_ci{
24098c2ecf20Sopenharmony_ci	atafb_get_var(&info->var, info);
24108c2ecf20Sopenharmony_ci	atafb_get_fix(&info->fix, info);
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci	/* Note: smem_start derives from phys_screen_base, not screen_base! */
24138c2ecf20Sopenharmony_ci	info->screen_base = (external_addr ? external_screen_base :
24148c2ecf20Sopenharmony_ci				atari_stram_to_virt(info->fix.smem_start));
24158c2ecf20Sopenharmony_ci}
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_cistatic int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
24188c2ecf20Sopenharmony_ci			   u_int transp, struct fb_info *info)
24198c2ecf20Sopenharmony_ci{
24208c2ecf20Sopenharmony_ci	red >>= 8;
24218c2ecf20Sopenharmony_ci	green >>= 8;
24228c2ecf20Sopenharmony_ci	blue >>= 8;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info);
24258c2ecf20Sopenharmony_ci}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_cistatic int
24288c2ecf20Sopenharmony_ciatafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
24298c2ecf20Sopenharmony_ci{
24308c2ecf20Sopenharmony_ci	int xoffset = var->xoffset;
24318c2ecf20Sopenharmony_ci	int yoffset = var->yoffset;
24328c2ecf20Sopenharmony_ci	int err;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_YWRAP) {
24358c2ecf20Sopenharmony_ci		if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset)
24368c2ecf20Sopenharmony_ci			return -EINVAL;
24378c2ecf20Sopenharmony_ci	} else {
24388c2ecf20Sopenharmony_ci		if (xoffset + info->var.xres > info->var.xres_virtual ||
24398c2ecf20Sopenharmony_ci		    yoffset + info->var.yres > info->var.yres_virtual)
24408c2ecf20Sopenharmony_ci			return -EINVAL;
24418c2ecf20Sopenharmony_ci	}
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	if (fbhw->pan_display) {
24448c2ecf20Sopenharmony_ci		err = fbhw->pan_display(var, info);
24458c2ecf20Sopenharmony_ci		if (err)
24468c2ecf20Sopenharmony_ci			return err;
24478c2ecf20Sopenharmony_ci	} else
24488c2ecf20Sopenharmony_ci		return -EINVAL;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci	info->var.xoffset = xoffset;
24518c2ecf20Sopenharmony_ci	info->var.yoffset = yoffset;
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_YWRAP)
24548c2ecf20Sopenharmony_ci		info->var.vmode |= FB_VMODE_YWRAP;
24558c2ecf20Sopenharmony_ci	else
24568c2ecf20Sopenharmony_ci		info->var.vmode &= ~FB_VMODE_YWRAP;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	return 0;
24598c2ecf20Sopenharmony_ci}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci/*
24628c2ecf20Sopenharmony_ci * generic drawing routines; imageblit needs updating for image depth > 1
24638c2ecf20Sopenharmony_ci */
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32
24668c2ecf20Sopenharmony_ci#define BYTES_PER_LONG	4
24678c2ecf20Sopenharmony_ci#define SHIFT_PER_LONG	5
24688c2ecf20Sopenharmony_ci#elif BITS_PER_LONG == 64
24698c2ecf20Sopenharmony_ci#define BYTES_PER_LONG	8
24708c2ecf20Sopenharmony_ci#define SHIFT_PER_LONG	6
24718c2ecf20Sopenharmony_ci#else
24728c2ecf20Sopenharmony_ci#define Please update me
24738c2ecf20Sopenharmony_ci#endif
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_cistatic void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
24778c2ecf20Sopenharmony_ci{
24788c2ecf20Sopenharmony_ci	struct atafb_par *par = (struct atafb_par *)info->par;
24798c2ecf20Sopenharmony_ci	int x2, y2;
24808c2ecf20Sopenharmony_ci	u32 width, height;
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	if (!rect->width || !rect->height)
24838c2ecf20Sopenharmony_ci		return;
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
24868c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 16) {
24878c2ecf20Sopenharmony_ci		cfb_fillrect(info, rect);
24888c2ecf20Sopenharmony_ci		return;
24898c2ecf20Sopenharmony_ci	}
24908c2ecf20Sopenharmony_ci#endif
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	/*
24938c2ecf20Sopenharmony_ci	 * We could use hardware clipping but on many cards you get around
24948c2ecf20Sopenharmony_ci	 * hardware clipping by writing to framebuffer directly.
24958c2ecf20Sopenharmony_ci	 * */
24968c2ecf20Sopenharmony_ci	x2 = rect->dx + rect->width;
24978c2ecf20Sopenharmony_ci	y2 = rect->dy + rect->height;
24988c2ecf20Sopenharmony_ci	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
24998c2ecf20Sopenharmony_ci	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
25008c2ecf20Sopenharmony_ci	width = x2 - rect->dx;
25018c2ecf20Sopenharmony_ci	height = y2 - rect->dy;
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 1)
25048c2ecf20Sopenharmony_ci		atafb_mfb_fillrect(info, par->next_line, rect->color,
25058c2ecf20Sopenharmony_ci				   rect->dy, rect->dx, height, width);
25068c2ecf20Sopenharmony_ci	else if (info->var.bits_per_pixel == 2)
25078c2ecf20Sopenharmony_ci		atafb_iplan2p2_fillrect(info, par->next_line, rect->color,
25088c2ecf20Sopenharmony_ci					rect->dy, rect->dx, height, width);
25098c2ecf20Sopenharmony_ci	else if (info->var.bits_per_pixel == 4)
25108c2ecf20Sopenharmony_ci		atafb_iplan2p4_fillrect(info, par->next_line, rect->color,
25118c2ecf20Sopenharmony_ci					rect->dy, rect->dx, height, width);
25128c2ecf20Sopenharmony_ci	else
25138c2ecf20Sopenharmony_ci		atafb_iplan2p8_fillrect(info, par->next_line, rect->color,
25148c2ecf20Sopenharmony_ci					rect->dy, rect->dx, height, width);
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	return;
25178c2ecf20Sopenharmony_ci}
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_cistatic void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
25208c2ecf20Sopenharmony_ci{
25218c2ecf20Sopenharmony_ci	struct atafb_par *par = (struct atafb_par *)info->par;
25228c2ecf20Sopenharmony_ci	int x2, y2;
25238c2ecf20Sopenharmony_ci	u32 dx, dy, sx, sy, width, height;
25248c2ecf20Sopenharmony_ci	int rev_copy = 0;
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
25278c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 16) {
25288c2ecf20Sopenharmony_ci		cfb_copyarea(info, area);
25298c2ecf20Sopenharmony_ci		return;
25308c2ecf20Sopenharmony_ci	}
25318c2ecf20Sopenharmony_ci#endif
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	/* clip the destination */
25348c2ecf20Sopenharmony_ci	x2 = area->dx + area->width;
25358c2ecf20Sopenharmony_ci	y2 = area->dy + area->height;
25368c2ecf20Sopenharmony_ci	dx = area->dx > 0 ? area->dx : 0;
25378c2ecf20Sopenharmony_ci	dy = area->dy > 0 ? area->dy : 0;
25388c2ecf20Sopenharmony_ci	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
25398c2ecf20Sopenharmony_ci	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
25408c2ecf20Sopenharmony_ci	width = x2 - dx;
25418c2ecf20Sopenharmony_ci	height = y2 - dy;
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	if (area->sx + dx < area->dx || area->sy + dy < area->dy)
25448c2ecf20Sopenharmony_ci		return;
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	/* update sx,sy */
25478c2ecf20Sopenharmony_ci	sx = area->sx + (dx - area->dx);
25488c2ecf20Sopenharmony_ci	sy = area->sy + (dy - area->dy);
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	/* the source must be completely inside the virtual screen */
25518c2ecf20Sopenharmony_ci	if (sx + width > info->var.xres_virtual ||
25528c2ecf20Sopenharmony_ci			sy + height > info->var.yres_virtual)
25538c2ecf20Sopenharmony_ci		return;
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	if (dy > sy || (dy == sy && dx > sx)) {
25568c2ecf20Sopenharmony_ci		dy += height;
25578c2ecf20Sopenharmony_ci		sy += height;
25588c2ecf20Sopenharmony_ci		rev_copy = 1;
25598c2ecf20Sopenharmony_ci	}
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 1)
25628c2ecf20Sopenharmony_ci		atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
25638c2ecf20Sopenharmony_ci	else if (info->var.bits_per_pixel == 2)
25648c2ecf20Sopenharmony_ci		atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
25658c2ecf20Sopenharmony_ci	else if (info->var.bits_per_pixel == 4)
25668c2ecf20Sopenharmony_ci		atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
25678c2ecf20Sopenharmony_ci	else
25688c2ecf20Sopenharmony_ci		atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci	return;
25718c2ecf20Sopenharmony_ci}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_cistatic void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
25748c2ecf20Sopenharmony_ci{
25758c2ecf20Sopenharmony_ci	struct atafb_par *par = (struct atafb_par *)info->par;
25768c2ecf20Sopenharmony_ci	int x2, y2;
25778c2ecf20Sopenharmony_ci	unsigned long *dst;
25788c2ecf20Sopenharmony_ci	int dst_idx;
25798c2ecf20Sopenharmony_ci	const char *src;
25808c2ecf20Sopenharmony_ci	u32 dx, dy, width, height, pitch;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
25838c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 16) {
25848c2ecf20Sopenharmony_ci		cfb_imageblit(info, image);
25858c2ecf20Sopenharmony_ci		return;
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci#endif
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	/*
25908c2ecf20Sopenharmony_ci	 * We could use hardware clipping but on many cards you get around
25918c2ecf20Sopenharmony_ci	 * hardware clipping by writing to framebuffer directly like we are
25928c2ecf20Sopenharmony_ci	 * doing here.
25938c2ecf20Sopenharmony_ci	 */
25948c2ecf20Sopenharmony_ci	x2 = image->dx + image->width;
25958c2ecf20Sopenharmony_ci	y2 = image->dy + image->height;
25968c2ecf20Sopenharmony_ci	dx = image->dx;
25978c2ecf20Sopenharmony_ci	dy = image->dy;
25988c2ecf20Sopenharmony_ci	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
25998c2ecf20Sopenharmony_ci	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
26008c2ecf20Sopenharmony_ci	width = x2 - dx;
26018c2ecf20Sopenharmony_ci	height = y2 - dy;
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	if (image->depth == 1) {
26048c2ecf20Sopenharmony_ci		// used for font data
26058c2ecf20Sopenharmony_ci		dst = (unsigned long *)
26068c2ecf20Sopenharmony_ci			((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
26078c2ecf20Sopenharmony_ci		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
26088c2ecf20Sopenharmony_ci		dst_idx += dy * par->next_line * 8 + dx;
26098c2ecf20Sopenharmony_ci		src = image->data;
26108c2ecf20Sopenharmony_ci		pitch = (image->width + 7) / 8;
26118c2ecf20Sopenharmony_ci		while (height--) {
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci			if (info->var.bits_per_pixel == 1)
26148c2ecf20Sopenharmony_ci				atafb_mfb_linefill(info, par->next_line,
26158c2ecf20Sopenharmony_ci						   dy, dx, width, src,
26168c2ecf20Sopenharmony_ci						   image->bg_color, image->fg_color);
26178c2ecf20Sopenharmony_ci			else if (info->var.bits_per_pixel == 2)
26188c2ecf20Sopenharmony_ci				atafb_iplan2p2_linefill(info, par->next_line,
26198c2ecf20Sopenharmony_ci							dy, dx, width, src,
26208c2ecf20Sopenharmony_ci							image->bg_color, image->fg_color);
26218c2ecf20Sopenharmony_ci			else if (info->var.bits_per_pixel == 4)
26228c2ecf20Sopenharmony_ci				atafb_iplan2p4_linefill(info, par->next_line,
26238c2ecf20Sopenharmony_ci							dy, dx, width, src,
26248c2ecf20Sopenharmony_ci							image->bg_color, image->fg_color);
26258c2ecf20Sopenharmony_ci			else
26268c2ecf20Sopenharmony_ci				atafb_iplan2p8_linefill(info, par->next_line,
26278c2ecf20Sopenharmony_ci							dy, dx, width, src,
26288c2ecf20Sopenharmony_ci							image->bg_color, image->fg_color);
26298c2ecf20Sopenharmony_ci			dy++;
26308c2ecf20Sopenharmony_ci			src += pitch;
26318c2ecf20Sopenharmony_ci		}
26328c2ecf20Sopenharmony_ci	} else {
26338c2ecf20Sopenharmony_ci		c2p_iplan2(info->screen_base, image->data, dx, dy, width,
26348c2ecf20Sopenharmony_ci			   height, par->next_line, image->width,
26358c2ecf20Sopenharmony_ci			   info->var.bits_per_pixel);
26368c2ecf20Sopenharmony_ci	}
26378c2ecf20Sopenharmony_ci}
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_cistatic int
26408c2ecf20Sopenharmony_ciatafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
26418c2ecf20Sopenharmony_ci{
26428c2ecf20Sopenharmony_ci	switch (cmd) {
26438c2ecf20Sopenharmony_ci#ifdef FBCMD_GET_CURRENTPAR
26448c2ecf20Sopenharmony_ci	case FBCMD_GET_CURRENTPAR:
26458c2ecf20Sopenharmony_ci		if (copy_to_user((void *)arg, (void *)&current_par,
26468c2ecf20Sopenharmony_ci				 sizeof(struct atafb_par)))
26478c2ecf20Sopenharmony_ci			return -EFAULT;
26488c2ecf20Sopenharmony_ci		return 0;
26498c2ecf20Sopenharmony_ci#endif
26508c2ecf20Sopenharmony_ci#ifdef FBCMD_SET_CURRENTPAR
26518c2ecf20Sopenharmony_ci	case FBCMD_SET_CURRENTPAR:
26528c2ecf20Sopenharmony_ci		if (copy_from_user((void *)&current_par, (void *)arg,
26538c2ecf20Sopenharmony_ci				   sizeof(struct atafb_par)))
26548c2ecf20Sopenharmony_ci			return -EFAULT;
26558c2ecf20Sopenharmony_ci		ata_set_par(&current_par);
26568c2ecf20Sopenharmony_ci		return 0;
26578c2ecf20Sopenharmony_ci#endif
26588c2ecf20Sopenharmony_ci	}
26598c2ecf20Sopenharmony_ci	return -EINVAL;
26608c2ecf20Sopenharmony_ci}
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci/* (un)blank/poweroff
26638c2ecf20Sopenharmony_ci * 0 = unblank
26648c2ecf20Sopenharmony_ci * 1 = blank
26658c2ecf20Sopenharmony_ci * 2 = suspend vsync
26668c2ecf20Sopenharmony_ci * 3 = suspend hsync
26678c2ecf20Sopenharmony_ci * 4 = off
26688c2ecf20Sopenharmony_ci */
26698c2ecf20Sopenharmony_cistatic int atafb_blank(int blank, struct fb_info *info)
26708c2ecf20Sopenharmony_ci{
26718c2ecf20Sopenharmony_ci	unsigned short black[16];
26728c2ecf20Sopenharmony_ci	struct fb_cmap cmap;
26738c2ecf20Sopenharmony_ci	if (fbhw->blank && !fbhw->blank(blank))
26748c2ecf20Sopenharmony_ci		return 1;
26758c2ecf20Sopenharmony_ci	if (blank) {
26768c2ecf20Sopenharmony_ci		memset(black, 0, 16 * sizeof(unsigned short));
26778c2ecf20Sopenharmony_ci		cmap.red = black;
26788c2ecf20Sopenharmony_ci		cmap.green = black;
26798c2ecf20Sopenharmony_ci		cmap.blue = black;
26808c2ecf20Sopenharmony_ci		cmap.transp = NULL;
26818c2ecf20Sopenharmony_ci		cmap.start = 0;
26828c2ecf20Sopenharmony_ci		cmap.len = 16;
26838c2ecf20Sopenharmony_ci		fb_set_cmap(&cmap, info);
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ci#if 0
26868c2ecf20Sopenharmony_ci	else
26878c2ecf20Sopenharmony_ci		do_install_cmap(info);
26888c2ecf20Sopenharmony_ci#endif
26898c2ecf20Sopenharmony_ci	return 0;
26908c2ecf20Sopenharmony_ci}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	/*
26938c2ecf20Sopenharmony_ci	 * New fbcon interface ...
26948c2ecf20Sopenharmony_ci	 */
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	 /* check var by decoding var into hw par, rounding if necessary,
26978c2ecf20Sopenharmony_ci	  * then encoding hw par back into new, validated var */
26988c2ecf20Sopenharmony_cistatic int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
26998c2ecf20Sopenharmony_ci{
27008c2ecf20Sopenharmony_ci	int err;
27018c2ecf20Sopenharmony_ci	struct atafb_par par;
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	/* Validate wanted screen parameters */
27048c2ecf20Sopenharmony_ci	// if ((err = ata_decode_var(var, &par)))
27058c2ecf20Sopenharmony_ci	err = fbhw->decode_var(var, &par);
27068c2ecf20Sopenharmony_ci	if (err)
27078c2ecf20Sopenharmony_ci		return err;
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	/* Encode (possibly rounded) screen parameters */
27108c2ecf20Sopenharmony_ci	fbhw->encode_var(var, &par);
27118c2ecf20Sopenharmony_ci	return 0;
27128c2ecf20Sopenharmony_ci}
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci	/* actually set hw par by decoding var, then setting hardware from
27158c2ecf20Sopenharmony_ci	 * hw par just decoded */
27168c2ecf20Sopenharmony_cistatic int atafb_set_par(struct fb_info *info)
27178c2ecf20Sopenharmony_ci{
27188c2ecf20Sopenharmony_ci	struct atafb_par *par = (struct atafb_par *)info->par;
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci	/* Decode wanted screen parameters */
27218c2ecf20Sopenharmony_ci	fbhw->decode_var(&info->var, par);
27228c2ecf20Sopenharmony_ci	mutex_lock(&info->mm_lock);
27238c2ecf20Sopenharmony_ci	fbhw->encode_fix(&info->fix, par);
27248c2ecf20Sopenharmony_ci	mutex_unlock(&info->mm_lock);
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	/* Set new videomode */
27278c2ecf20Sopenharmony_ci	ata_set_par(par);
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	return 0;
27308c2ecf20Sopenharmony_ci}
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_cistatic struct fb_ops atafb_ops = {
27348c2ecf20Sopenharmony_ci	.owner =	THIS_MODULE,
27358c2ecf20Sopenharmony_ci	.fb_check_var	= atafb_check_var,
27368c2ecf20Sopenharmony_ci	.fb_set_par	= atafb_set_par,
27378c2ecf20Sopenharmony_ci	.fb_setcolreg	= atafb_setcolreg,
27388c2ecf20Sopenharmony_ci	.fb_blank =	atafb_blank,
27398c2ecf20Sopenharmony_ci	.fb_pan_display	= atafb_pan_display,
27408c2ecf20Sopenharmony_ci	.fb_fillrect	= atafb_fillrect,
27418c2ecf20Sopenharmony_ci	.fb_copyarea	= atafb_copyarea,
27428c2ecf20Sopenharmony_ci	.fb_imageblit	= atafb_imageblit,
27438c2ecf20Sopenharmony_ci	.fb_ioctl =	atafb_ioctl,
27448c2ecf20Sopenharmony_ci};
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_cistatic void check_default_par(int detected_mode)
27478c2ecf20Sopenharmony_ci{
27488c2ecf20Sopenharmony_ci	char default_name[10];
27498c2ecf20Sopenharmony_ci	int i;
27508c2ecf20Sopenharmony_ci	struct fb_var_screeninfo var;
27518c2ecf20Sopenharmony_ci	unsigned long min_mem;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	/* First try the user supplied mode */
27548c2ecf20Sopenharmony_ci	if (default_par) {
27558c2ecf20Sopenharmony_ci		var = atafb_predefined[default_par - 1];
27568c2ecf20Sopenharmony_ci		var.activate = FB_ACTIVATE_TEST;
27578c2ecf20Sopenharmony_ci		if (do_fb_set_var(&var, 1))
27588c2ecf20Sopenharmony_ci			default_par = 0;	/* failed */
27598c2ecf20Sopenharmony_ci	}
27608c2ecf20Sopenharmony_ci	/* Next is the autodetected one */
27618c2ecf20Sopenharmony_ci	if (!default_par) {
27628c2ecf20Sopenharmony_ci		var = atafb_predefined[detected_mode - 1]; /* autodetect */
27638c2ecf20Sopenharmony_ci		var.activate = FB_ACTIVATE_TEST;
27648c2ecf20Sopenharmony_ci		if (!do_fb_set_var(&var, 1))
27658c2ecf20Sopenharmony_ci			default_par = detected_mode;
27668c2ecf20Sopenharmony_ci	}
27678c2ecf20Sopenharmony_ci	/* If that also failed, try some default modes... */
27688c2ecf20Sopenharmony_ci	if (!default_par) {
27698c2ecf20Sopenharmony_ci		/* try default1, default2... */
27708c2ecf20Sopenharmony_ci		for (i = 1; i < 10; i++) {
27718c2ecf20Sopenharmony_ci			sprintf(default_name,"default%d", i);
27728c2ecf20Sopenharmony_ci			default_par = get_video_mode(default_name);
27738c2ecf20Sopenharmony_ci			if (!default_par)
27748c2ecf20Sopenharmony_ci				panic("can't set default video mode");
27758c2ecf20Sopenharmony_ci			var = atafb_predefined[default_par - 1];
27768c2ecf20Sopenharmony_ci			var.activate = FB_ACTIVATE_TEST;
27778c2ecf20Sopenharmony_ci			if (!do_fb_set_var(&var,1))
27788c2ecf20Sopenharmony_ci				break;	/* ok */
27798c2ecf20Sopenharmony_ci		}
27808c2ecf20Sopenharmony_ci	}
27818c2ecf20Sopenharmony_ci	min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8;
27828c2ecf20Sopenharmony_ci	if (default_mem_req < min_mem)
27838c2ecf20Sopenharmony_ci		default_mem_req = min_mem;
27848c2ecf20Sopenharmony_ci}
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
27878c2ecf20Sopenharmony_cistatic void __init atafb_setup_ext(char *spec)
27888c2ecf20Sopenharmony_ci{
27898c2ecf20Sopenharmony_ci	int xres, xres_virtual, yres, depth, planes;
27908c2ecf20Sopenharmony_ci	unsigned long addr, len;
27918c2ecf20Sopenharmony_ci	char *p;
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci	/* Format is: <xres>;<yres>;<depth>;<plane organ.>;
27948c2ecf20Sopenharmony_ci	 *            <screen mem addr>
27958c2ecf20Sopenharmony_ci	 *	      [;<screen mem length>[;<vgaiobase>[;<bits-per-col>[;<colorreg-type>
27968c2ecf20Sopenharmony_ci	 *	      [;<xres-virtual>]]]]]
27978c2ecf20Sopenharmony_ci	 *
27988c2ecf20Sopenharmony_ci	 * 09/23/97	Juergen
27998c2ecf20Sopenharmony_ci	 * <xres_virtual>:	hardware's x-resolution (f.e. ProMST)
28008c2ecf20Sopenharmony_ci	 *
28018c2ecf20Sopenharmony_ci	 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
28028c2ecf20Sopenharmony_ci	 */
28038c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28048c2ecf20Sopenharmony_ci	if (!p || !*p)
28058c2ecf20Sopenharmony_ci		return;
28068c2ecf20Sopenharmony_ci	xres_virtual = xres = simple_strtoul(p, NULL, 10);
28078c2ecf20Sopenharmony_ci	if (xres <= 0)
28088c2ecf20Sopenharmony_ci		return;
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28118c2ecf20Sopenharmony_ci	if (!p || !*p)
28128c2ecf20Sopenharmony_ci		return;
28138c2ecf20Sopenharmony_ci	yres = simple_strtoul(p, NULL, 10);
28148c2ecf20Sopenharmony_ci	if (yres <= 0)
28158c2ecf20Sopenharmony_ci		return;
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28188c2ecf20Sopenharmony_ci	if (!p || !*p)
28198c2ecf20Sopenharmony_ci		return;
28208c2ecf20Sopenharmony_ci	depth = simple_strtoul(p, NULL, 10);
28218c2ecf20Sopenharmony_ci	if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
28228c2ecf20Sopenharmony_ci	    depth != 16 && depth != 24)
28238c2ecf20Sopenharmony_ci		return;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28268c2ecf20Sopenharmony_ci	if (!p || !*p)
28278c2ecf20Sopenharmony_ci		return;
28288c2ecf20Sopenharmony_ci	if (*p == 'i')
28298c2ecf20Sopenharmony_ci		planes = FB_TYPE_INTERLEAVED_PLANES;
28308c2ecf20Sopenharmony_ci	else if (*p == 'p')
28318c2ecf20Sopenharmony_ci		planes = FB_TYPE_PACKED_PIXELS;
28328c2ecf20Sopenharmony_ci	else if (*p == 'n')
28338c2ecf20Sopenharmony_ci		planes = FB_TYPE_PLANES;
28348c2ecf20Sopenharmony_ci	else if (*p == 't')
28358c2ecf20Sopenharmony_ci		planes = -1;		/* true color */
28368c2ecf20Sopenharmony_ci	else
28378c2ecf20Sopenharmony_ci		return;
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28408c2ecf20Sopenharmony_ci	if (!p || !*p)
28418c2ecf20Sopenharmony_ci		return;
28428c2ecf20Sopenharmony_ci	addr = simple_strtoul(p, NULL, 0);
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28458c2ecf20Sopenharmony_ci	if (!p || !*p)
28468c2ecf20Sopenharmony_ci		len = xres * yres * depth / 8;
28478c2ecf20Sopenharmony_ci	else
28488c2ecf20Sopenharmony_ci		len = simple_strtoul(p, NULL, 0);
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28518c2ecf20Sopenharmony_ci	if (p && *p)
28528c2ecf20Sopenharmony_ci		external_vgaiobase = simple_strtoul(p, NULL, 0);
28538c2ecf20Sopenharmony_ci
28548c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28558c2ecf20Sopenharmony_ci	if (p && *p) {
28568c2ecf20Sopenharmony_ci		external_bitspercol = simple_strtoul(p, NULL, 0);
28578c2ecf20Sopenharmony_ci		if (external_bitspercol > 8)
28588c2ecf20Sopenharmony_ci			external_bitspercol = 8;
28598c2ecf20Sopenharmony_ci		else if (external_bitspercol < 1)
28608c2ecf20Sopenharmony_ci			external_bitspercol = 1;
28618c2ecf20Sopenharmony_ci	}
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28648c2ecf20Sopenharmony_ci	if (p && *p) {
28658c2ecf20Sopenharmony_ci		if (!strcmp(p, "vga"))
28668c2ecf20Sopenharmony_ci			external_card_type = IS_VGA;
28678c2ecf20Sopenharmony_ci		if (!strcmp(p, "mv300"))
28688c2ecf20Sopenharmony_ci			external_card_type = IS_MV300;
28698c2ecf20Sopenharmony_ci	}
28708c2ecf20Sopenharmony_ci
28718c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
28728c2ecf20Sopenharmony_ci	if (p && *p) {
28738c2ecf20Sopenharmony_ci		xres_virtual = simple_strtoul(p, NULL, 10);
28748c2ecf20Sopenharmony_ci		if (xres_virtual < xres)
28758c2ecf20Sopenharmony_ci			xres_virtual = xres;
28768c2ecf20Sopenharmony_ci		if (xres_virtual * yres * depth / 8 > len)
28778c2ecf20Sopenharmony_ci			len = xres_virtual * yres * depth / 8;
28788c2ecf20Sopenharmony_ci	}
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	external_xres = xres;
28818c2ecf20Sopenharmony_ci	external_xres_virtual = xres_virtual;
28828c2ecf20Sopenharmony_ci	external_yres = yres;
28838c2ecf20Sopenharmony_ci	external_depth = depth;
28848c2ecf20Sopenharmony_ci	external_pmode = planes;
28858c2ecf20Sopenharmony_ci	external_addr = addr;
28868c2ecf20Sopenharmony_ci	external_len = len;
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_ci	if (external_card_type == IS_MV300) {
28898c2ecf20Sopenharmony_ci		switch (external_depth) {
28908c2ecf20Sopenharmony_ci		case 1:
28918c2ecf20Sopenharmony_ci			MV300_reg = MV300_reg_1bit;
28928c2ecf20Sopenharmony_ci			break;
28938c2ecf20Sopenharmony_ci		case 4:
28948c2ecf20Sopenharmony_ci			MV300_reg = MV300_reg_4bit;
28958c2ecf20Sopenharmony_ci			break;
28968c2ecf20Sopenharmony_ci		case 8:
28978c2ecf20Sopenharmony_ci			MV300_reg = MV300_reg_8bit;
28988c2ecf20Sopenharmony_ci			break;
28998c2ecf20Sopenharmony_ci		}
29008c2ecf20Sopenharmony_ci	}
29018c2ecf20Sopenharmony_ci}
29028c2ecf20Sopenharmony_ci#endif /* ATAFB_EXT */
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_cistatic void __init atafb_setup_int(char *spec)
29058c2ecf20Sopenharmony_ci{
29068c2ecf20Sopenharmony_ci	/* Format to config extended internal video hardware like OverScan:
29078c2ecf20Sopenharmony_ci	 * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
29088c2ecf20Sopenharmony_ci	 * Explanation:
29098c2ecf20Sopenharmony_ci	 * <xres>: x-resolution
29108c2ecf20Sopenharmony_ci	 * <yres>: y-resolution
29118c2ecf20Sopenharmony_ci	 * The following are only needed if you have an overscan which
29128c2ecf20Sopenharmony_ci	 * needs a black border:
29138c2ecf20Sopenharmony_ci	 * <xres_max>: max. length of a line in pixels your OverScan hardware would allow
29148c2ecf20Sopenharmony_ci	 * <yres_max>: max. number of lines your OverScan hardware would allow
29158c2ecf20Sopenharmony_ci	 * <offset>: Offset from physical beginning to visible beginning
29168c2ecf20Sopenharmony_ci	 *	  of screen in bytes
29178c2ecf20Sopenharmony_ci	 */
29188c2ecf20Sopenharmony_ci	int xres;
29198c2ecf20Sopenharmony_ci	char *p;
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci	if (!(p = strsep(&spec, ";")) || !*p)
29228c2ecf20Sopenharmony_ci		return;
29238c2ecf20Sopenharmony_ci	xres = simple_strtoul(p, NULL, 10);
29248c2ecf20Sopenharmony_ci	if (!(p = strsep(&spec, ";")) || !*p)
29258c2ecf20Sopenharmony_ci		return;
29268c2ecf20Sopenharmony_ci	sttt_xres = xres;
29278c2ecf20Sopenharmony_ci	tt_yres = st_yres = simple_strtoul(p, NULL, 10);
29288c2ecf20Sopenharmony_ci	if ((p = strsep(&spec, ";")) && *p)
29298c2ecf20Sopenharmony_ci		sttt_xres_virtual = simple_strtoul(p, NULL, 10);
29308c2ecf20Sopenharmony_ci	if ((p = strsep(&spec, ";")) && *p)
29318c2ecf20Sopenharmony_ci		sttt_yres_virtual = simple_strtoul(p, NULL, 0);
29328c2ecf20Sopenharmony_ci	if ((p = strsep(&spec, ";")) && *p)
29338c2ecf20Sopenharmony_ci		ovsc_offset = simple_strtoul(p, NULL, 0);
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	if (ovsc_offset || (sttt_yres_virtual != st_yres))
29368c2ecf20Sopenharmony_ci		use_hwscroll = 0;
29378c2ecf20Sopenharmony_ci}
29388c2ecf20Sopenharmony_ci
29398c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
29408c2ecf20Sopenharmony_cistatic void __init atafb_setup_mcap(char *spec)
29418c2ecf20Sopenharmony_ci{
29428c2ecf20Sopenharmony_ci	char *p;
29438c2ecf20Sopenharmony_ci	int vmin, vmax, hmin, hmax;
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
29468c2ecf20Sopenharmony_ci	 * <V*> vertical freq. in Hz
29478c2ecf20Sopenharmony_ci	 * <H*> horizontal freq. in kHz
29488c2ecf20Sopenharmony_ci	 */
29498c2ecf20Sopenharmony_ci	if (!(p = strsep(&spec, ";")) || !*p)
29508c2ecf20Sopenharmony_ci		return;
29518c2ecf20Sopenharmony_ci	vmin = simple_strtoul(p, NULL, 10);
29528c2ecf20Sopenharmony_ci	if (vmin <= 0)
29538c2ecf20Sopenharmony_ci		return;
29548c2ecf20Sopenharmony_ci	if (!(p = strsep(&spec, ";")) || !*p)
29558c2ecf20Sopenharmony_ci		return;
29568c2ecf20Sopenharmony_ci	vmax = simple_strtoul(p, NULL, 10);
29578c2ecf20Sopenharmony_ci	if (vmax <= 0 || vmax <= vmin)
29588c2ecf20Sopenharmony_ci		return;
29598c2ecf20Sopenharmony_ci	if (!(p = strsep(&spec, ";")) || !*p)
29608c2ecf20Sopenharmony_ci		return;
29618c2ecf20Sopenharmony_ci	hmin = 1000 * simple_strtoul(p, NULL, 10);
29628c2ecf20Sopenharmony_ci	if (hmin <= 0)
29638c2ecf20Sopenharmony_ci		return;
29648c2ecf20Sopenharmony_ci	if (!(p = strsep(&spec, "")) || !*p)
29658c2ecf20Sopenharmony_ci		return;
29668c2ecf20Sopenharmony_ci	hmax = 1000 * simple_strtoul(p, NULL, 10);
29678c2ecf20Sopenharmony_ci	if (hmax <= 0 || hmax <= hmin)
29688c2ecf20Sopenharmony_ci		return;
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	fb_info.monspecs.vfmin = vmin;
29718c2ecf20Sopenharmony_ci	fb_info.monspecs.vfmax = vmax;
29728c2ecf20Sopenharmony_ci	fb_info.monspecs.hfmin = hmin;
29738c2ecf20Sopenharmony_ci	fb_info.monspecs.hfmax = hmax;
29748c2ecf20Sopenharmony_ci}
29758c2ecf20Sopenharmony_ci#endif /* ATAFB_FALCON */
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_cistatic void __init atafb_setup_user(char *spec)
29788c2ecf20Sopenharmony_ci{
29798c2ecf20Sopenharmony_ci	/* Format of user defined video mode is: <xres>;<yres>;<depth>
29808c2ecf20Sopenharmony_ci	 */
29818c2ecf20Sopenharmony_ci	char *p;
29828c2ecf20Sopenharmony_ci	int xres, yres, depth, temp;
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
29858c2ecf20Sopenharmony_ci	if (!p || !*p)
29868c2ecf20Sopenharmony_ci		return;
29878c2ecf20Sopenharmony_ci	xres = simple_strtoul(p, NULL, 10);
29888c2ecf20Sopenharmony_ci	p = strsep(&spec, ";");
29898c2ecf20Sopenharmony_ci	if (!p || !*p)
29908c2ecf20Sopenharmony_ci		return;
29918c2ecf20Sopenharmony_ci	yres = simple_strtoul(p, NULL, 10);
29928c2ecf20Sopenharmony_ci	p = strsep(&spec, "");
29938c2ecf20Sopenharmony_ci	if (!p || !*p)
29948c2ecf20Sopenharmony_ci		return;
29958c2ecf20Sopenharmony_ci	depth = simple_strtoul(p, NULL, 10);
29968c2ecf20Sopenharmony_ci	temp = get_video_mode("user0");
29978c2ecf20Sopenharmony_ci	if (temp) {
29988c2ecf20Sopenharmony_ci		default_par = temp;
29998c2ecf20Sopenharmony_ci		atafb_predefined[default_par - 1].xres = xres;
30008c2ecf20Sopenharmony_ci		atafb_predefined[default_par - 1].yres = yres;
30018c2ecf20Sopenharmony_ci		atafb_predefined[default_par - 1].bits_per_pixel = depth;
30028c2ecf20Sopenharmony_ci	}
30038c2ecf20Sopenharmony_ci}
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ciint __init atafb_setup(char *options)
30068c2ecf20Sopenharmony_ci{
30078c2ecf20Sopenharmony_ci	char *this_opt;
30088c2ecf20Sopenharmony_ci	int temp;
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	if (!options || !*options)
30118c2ecf20Sopenharmony_ci		return 0;
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
30148c2ecf20Sopenharmony_ci		if (!*this_opt)
30158c2ecf20Sopenharmony_ci			continue;
30168c2ecf20Sopenharmony_ci		if ((temp = get_video_mode(this_opt))) {
30178c2ecf20Sopenharmony_ci			default_par = temp;
30188c2ecf20Sopenharmony_ci			mode_option = this_opt;
30198c2ecf20Sopenharmony_ci		} else if (!strcmp(this_opt, "inverse"))
30208c2ecf20Sopenharmony_ci			inverse = 1;
30218c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "hwscroll_", 9)) {
30228c2ecf20Sopenharmony_ci			hwscroll = simple_strtoul(this_opt + 9, NULL, 10);
30238c2ecf20Sopenharmony_ci			if (hwscroll < 0)
30248c2ecf20Sopenharmony_ci				hwscroll = 0;
30258c2ecf20Sopenharmony_ci			if (hwscroll > 200)
30268c2ecf20Sopenharmony_ci				hwscroll = 200;
30278c2ecf20Sopenharmony_ci		}
30288c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
30298c2ecf20Sopenharmony_ci		else if (!strcmp(this_opt, "mv300")) {
30308c2ecf20Sopenharmony_ci			external_bitspercol = 8;
30318c2ecf20Sopenharmony_ci			external_card_type = IS_MV300;
30328c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "external:", 9))
30338c2ecf20Sopenharmony_ci			atafb_setup_ext(this_opt + 9);
30348c2ecf20Sopenharmony_ci#endif
30358c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "internal:", 9))
30368c2ecf20Sopenharmony_ci			atafb_setup_int(this_opt + 9);
30378c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
30388c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "eclock:", 7)) {
30398c2ecf20Sopenharmony_ci			fext.f = simple_strtoul(this_opt + 7, NULL, 10);
30408c2ecf20Sopenharmony_ci			/* external pixelclock in kHz --> ps */
30418c2ecf20Sopenharmony_ci			fext.t = 1000000000 / fext.f;
30428c2ecf20Sopenharmony_ci			fext.f *= 1000;
30438c2ecf20Sopenharmony_ci		} else if (!strncmp(this_opt, "monitorcap:", 11))
30448c2ecf20Sopenharmony_ci			atafb_setup_mcap(this_opt + 11);
30458c2ecf20Sopenharmony_ci#endif
30468c2ecf20Sopenharmony_ci		else if (!strcmp(this_opt, "keep"))
30478c2ecf20Sopenharmony_ci			DontCalcRes = 1;
30488c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "R", 1))
30498c2ecf20Sopenharmony_ci			atafb_setup_user(this_opt + 1);
30508c2ecf20Sopenharmony_ci	}
30518c2ecf20Sopenharmony_ci	return 0;
30528c2ecf20Sopenharmony_ci}
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_cistatic int __init atafb_probe(struct platform_device *pdev)
30558c2ecf20Sopenharmony_ci{
30568c2ecf20Sopenharmony_ci	int pad, detected_mode, error;
30578c2ecf20Sopenharmony_ci	unsigned int defmode = 0;
30588c2ecf20Sopenharmony_ci	unsigned long mem_req;
30598c2ecf20Sopenharmony_ci	char *option = NULL;
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci	if (fb_get_options("atafb", &option))
30628c2ecf20Sopenharmony_ci		return -ENODEV;
30638c2ecf20Sopenharmony_ci	atafb_setup(option);
30648c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "%s: start\n", __func__);
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci	do {
30678c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
30688c2ecf20Sopenharmony_ci		if (external_addr) {
30698c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev, "initializing external hw\n");
30708c2ecf20Sopenharmony_ci			fbhw = &ext_switch;
30718c2ecf20Sopenharmony_ci			atafb_ops.fb_setcolreg = &ext_setcolreg;
30728c2ecf20Sopenharmony_ci			defmode = DEFMODE_EXT;
30738c2ecf20Sopenharmony_ci			break;
30748c2ecf20Sopenharmony_ci		}
30758c2ecf20Sopenharmony_ci#endif
30768c2ecf20Sopenharmony_ci#ifdef ATAFB_TT
30778c2ecf20Sopenharmony_ci		if (ATARIHW_PRESENT(TT_SHIFTER)) {
30788c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev, "initializing TT hw\n");
30798c2ecf20Sopenharmony_ci			fbhw = &tt_switch;
30808c2ecf20Sopenharmony_ci			atafb_ops.fb_setcolreg = &tt_setcolreg;
30818c2ecf20Sopenharmony_ci			defmode = DEFMODE_TT;
30828c2ecf20Sopenharmony_ci			break;
30838c2ecf20Sopenharmony_ci		}
30848c2ecf20Sopenharmony_ci#endif
30858c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
30868c2ecf20Sopenharmony_ci		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
30878c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev, "initializing Falcon hw\n");
30888c2ecf20Sopenharmony_ci			fbhw = &falcon_switch;
30898c2ecf20Sopenharmony_ci			atafb_ops.fb_setcolreg = &falcon_setcolreg;
30908c2ecf20Sopenharmony_ci			error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, 0,
30918c2ecf20Sopenharmony_ci					    "framebuffer:modeswitch",
30928c2ecf20Sopenharmony_ci					    falcon_vbl_switcher);
30938c2ecf20Sopenharmony_ci			if (error)
30948c2ecf20Sopenharmony_ci				return error;
30958c2ecf20Sopenharmony_ci			defmode = DEFMODE_F30;
30968c2ecf20Sopenharmony_ci			break;
30978c2ecf20Sopenharmony_ci		}
30988c2ecf20Sopenharmony_ci#endif
30998c2ecf20Sopenharmony_ci#ifdef ATAFB_STE
31008c2ecf20Sopenharmony_ci		if (ATARIHW_PRESENT(STND_SHIFTER) ||
31018c2ecf20Sopenharmony_ci		    ATARIHW_PRESENT(EXTD_SHIFTER)) {
31028c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev, "initializing ST/E hw\n");
31038c2ecf20Sopenharmony_ci			fbhw = &st_switch;
31048c2ecf20Sopenharmony_ci			atafb_ops.fb_setcolreg = &stste_setcolreg;
31058c2ecf20Sopenharmony_ci			defmode = DEFMODE_STE;
31068c2ecf20Sopenharmony_ci			break;
31078c2ecf20Sopenharmony_ci		}
31088c2ecf20Sopenharmony_ci		fbhw = &st_switch;
31098c2ecf20Sopenharmony_ci		atafb_ops.fb_setcolreg = &stste_setcolreg;
31108c2ecf20Sopenharmony_ci		dev_warn(&pdev->dev,
31118c2ecf20Sopenharmony_ci			 "Cannot determine video hardware; defaulting to ST(e)\n");
31128c2ecf20Sopenharmony_ci#else /* ATAFB_STE */
31138c2ecf20Sopenharmony_ci		/* no default driver included */
31148c2ecf20Sopenharmony_ci		/* Nobody will ever see this message :-) */
31158c2ecf20Sopenharmony_ci		panic("Cannot initialize video hardware");
31168c2ecf20Sopenharmony_ci#endif
31178c2ecf20Sopenharmony_ci	} while (0);
31188c2ecf20Sopenharmony_ci
31198c2ecf20Sopenharmony_ci	/* Multisync monitor capabilities */
31208c2ecf20Sopenharmony_ci	/* Atari-TOS defaults if no boot option present */
31218c2ecf20Sopenharmony_ci	if (fb_info.monspecs.hfmin == 0) {
31228c2ecf20Sopenharmony_ci		fb_info.monspecs.hfmin = 31000;
31238c2ecf20Sopenharmony_ci		fb_info.monspecs.hfmax = 32000;
31248c2ecf20Sopenharmony_ci		fb_info.monspecs.vfmin = 58;
31258c2ecf20Sopenharmony_ci		fb_info.monspecs.vfmax = 62;
31268c2ecf20Sopenharmony_ci	}
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci	detected_mode = fbhw->detect();
31298c2ecf20Sopenharmony_ci	check_default_par(detected_mode);
31308c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
31318c2ecf20Sopenharmony_ci	if (!external_addr) {
31328c2ecf20Sopenharmony_ci#endif /* ATAFB_EXT */
31338c2ecf20Sopenharmony_ci		mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
31348c2ecf20Sopenharmony_ci		mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
31358c2ecf20Sopenharmony_ci		screen_base = atari_stram_alloc(mem_req, "atafb");
31368c2ecf20Sopenharmony_ci		if (!screen_base)
31378c2ecf20Sopenharmony_ci			panic("Cannot allocate screen memory");
31388c2ecf20Sopenharmony_ci		memset(screen_base, 0, mem_req);
31398c2ecf20Sopenharmony_ci		pad = -(unsigned long)screen_base & (PAGE_SIZE - 1);
31408c2ecf20Sopenharmony_ci		screen_base += pad;
31418c2ecf20Sopenharmony_ci		phys_screen_base = atari_stram_to_phys(screen_base + ovsc_offset);
31428c2ecf20Sopenharmony_ci		screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
31438c2ecf20Sopenharmony_ci		st_ovsc_switch();
31448c2ecf20Sopenharmony_ci		if (CPU_IS_040_OR_060) {
31458c2ecf20Sopenharmony_ci			/* On a '040+, the cache mode of video RAM must be set to
31468c2ecf20Sopenharmony_ci			 * write-through also for internal video hardware! */
31478c2ecf20Sopenharmony_ci			cache_push(atari_stram_to_phys(screen_base), screen_len);
31488c2ecf20Sopenharmony_ci			kernel_set_cachemode(screen_base, screen_len,
31498c2ecf20Sopenharmony_ci					     IOMAP_WRITETHROUGH);
31508c2ecf20Sopenharmony_ci		}
31518c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "phys_screen_base %lx screen_len %d\n",
31528c2ecf20Sopenharmony_ci			 phys_screen_base, screen_len);
31538c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
31548c2ecf20Sopenharmony_ci	} else {
31558c2ecf20Sopenharmony_ci		/* Map the video memory (physical address given) to somewhere
31568c2ecf20Sopenharmony_ci		 * in the kernel address space.
31578c2ecf20Sopenharmony_ci		 */
31588c2ecf20Sopenharmony_ci		external_screen_base = ioremap_wt(external_addr, external_len);
31598c2ecf20Sopenharmony_ci		if (external_vgaiobase)
31608c2ecf20Sopenharmony_ci			external_vgaiobase =
31618c2ecf20Sopenharmony_ci			  (unsigned long)ioremap(external_vgaiobase, 0x10000);
31628c2ecf20Sopenharmony_ci		screen_base = external_screen_base;
31638c2ecf20Sopenharmony_ci		phys_screen_base = external_addr;
31648c2ecf20Sopenharmony_ci		screen_len = external_len & PAGE_MASK;
31658c2ecf20Sopenharmony_ci		memset (screen_base, 0, external_len);
31668c2ecf20Sopenharmony_ci	}
31678c2ecf20Sopenharmony_ci#endif /* ATAFB_EXT */
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci//	strcpy(fb_info.mode->name, "Atari Builtin ");
31708c2ecf20Sopenharmony_ci	fb_info.fbops = &atafb_ops;
31718c2ecf20Sopenharmony_ci	// try to set default (detected; requested) var
31728c2ecf20Sopenharmony_ci	do_fb_set_var(&atafb_predefined[default_par - 1], 1);
31738c2ecf20Sopenharmony_ci	// reads hw state into current par, which may not be sane yet
31748c2ecf20Sopenharmony_ci	ata_get_par(&current_par);
31758c2ecf20Sopenharmony_ci	fb_info.par = &current_par;
31768c2ecf20Sopenharmony_ci	// tries to read from HW which may not be initialized yet
31778c2ecf20Sopenharmony_ci	// so set sane var first, then call atafb_set_par
31788c2ecf20Sopenharmony_ci	atafb_get_var(&fb_info.var, &fb_info);
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci#ifdef ATAFB_FALCON
31818c2ecf20Sopenharmony_ci	fb_info.pseudo_palette = current_par.hw.falcon.pseudo_palette;
31828c2ecf20Sopenharmony_ci#endif
31838c2ecf20Sopenharmony_ci	fb_info.flags = FBINFO_FLAG_DEFAULT;
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
31868c2ecf20Sopenharmony_ci			  NUM_TOTAL_MODES, &atafb_modedb[defmode],
31878c2ecf20Sopenharmony_ci			  fb_info.var.bits_per_pixel)) {
31888c2ecf20Sopenharmony_ci		return -EINVAL;
31898c2ecf20Sopenharmony_ci	}
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	fb_videomode_to_modelist(atafb_modedb, NUM_TOTAL_MODES,
31928c2ecf20Sopenharmony_ci				 &fb_info.modelist);
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci	atafb_set_disp(&fb_info);
31958c2ecf20Sopenharmony_ci
31968c2ecf20Sopenharmony_ci	fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "Determined %dx%d, depth %d\n", fb_info.var.xres,
32008c2ecf20Sopenharmony_ci		 fb_info.var.yres, fb_info.var.bits_per_pixel);
32018c2ecf20Sopenharmony_ci	if ((fb_info.var.xres != fb_info.var.xres_virtual) ||
32028c2ecf20Sopenharmony_ci	    (fb_info.var.yres != fb_info.var.yres_virtual))
32038c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "   virtual %dx%d\n",
32048c2ecf20Sopenharmony_ci			 fb_info.var.xres_virtual, fb_info.var.yres_virtual);
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	if (register_framebuffer(&fb_info) < 0) {
32078c2ecf20Sopenharmony_ci#ifdef ATAFB_EXT
32088c2ecf20Sopenharmony_ci		if (external_addr) {
32098c2ecf20Sopenharmony_ci			iounmap(external_screen_base);
32108c2ecf20Sopenharmony_ci			external_addr = 0;
32118c2ecf20Sopenharmony_ci		}
32128c2ecf20Sopenharmony_ci		if (external_vgaiobase) {
32138c2ecf20Sopenharmony_ci			iounmap((void*)external_vgaiobase);
32148c2ecf20Sopenharmony_ci			external_vgaiobase = 0;
32158c2ecf20Sopenharmony_ci		}
32168c2ecf20Sopenharmony_ci#endif
32178c2ecf20Sopenharmony_ci		return -EINVAL;
32188c2ecf20Sopenharmony_ci	}
32198c2ecf20Sopenharmony_ci
32208c2ecf20Sopenharmony_ci	fb_info(&fb_info, "frame buffer device, using %dK of video memory\n",
32218c2ecf20Sopenharmony_ci		screen_len >> 10);
32228c2ecf20Sopenharmony_ci
32238c2ecf20Sopenharmony_ci	/* TODO: This driver cannot be unloaded yet */
32248c2ecf20Sopenharmony_ci	return 0;
32258c2ecf20Sopenharmony_ci}
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_cistatic void atafb_shutdown(struct platform_device *pdev)
32288c2ecf20Sopenharmony_ci{
32298c2ecf20Sopenharmony_ci	/* Unblank before kexec */
32308c2ecf20Sopenharmony_ci	if (fbhw->blank)
32318c2ecf20Sopenharmony_ci		fbhw->blank(0);
32328c2ecf20Sopenharmony_ci}
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_cistatic struct platform_driver atafb_driver = {
32358c2ecf20Sopenharmony_ci	.shutdown	= atafb_shutdown,
32368c2ecf20Sopenharmony_ci	.driver	= {
32378c2ecf20Sopenharmony_ci		.name	= "atafb",
32388c2ecf20Sopenharmony_ci	},
32398c2ecf20Sopenharmony_ci};
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_cistatic int __init atafb_init(void)
32428c2ecf20Sopenharmony_ci{
32438c2ecf20Sopenharmony_ci	struct platform_device *pdev;
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	if (!MACH_IS_ATARI)
32468c2ecf20Sopenharmony_ci		return -ENODEV;
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci	pdev = platform_device_register_simple("atafb", -1, NULL, 0);
32498c2ecf20Sopenharmony_ci	if (IS_ERR(pdev))
32508c2ecf20Sopenharmony_ci		return PTR_ERR(pdev);
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci	return platform_driver_probe(&atafb_driver, atafb_probe);
32538c2ecf20Sopenharmony_ci}
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_cidevice_initcall(atafb_init);
3256