162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Contributors (thanks, all!)
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *	David Eger:
962306a36Sopenharmony_ci *	Overhaul for Linux 2.6
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *      Jeff Rugen:
1262306a36Sopenharmony_ci *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
1362306a36Sopenharmony_ci *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *	Geert Uytterhoeven:
1662306a36Sopenharmony_ci *	Excellent code review.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *	Lars Hecking:
1962306a36Sopenharmony_ci *	Amiga updates and testing.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Original cirrusfb author:  Frank Neumann
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Based on retz3fb.c and cirrusfb.c:
2462306a36Sopenharmony_ci *      Copyright (C) 1997 Jes Sorensen
2562306a36Sopenharmony_ci *      Copyright (C) 1996 Frank Neumann
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci ***************************************************************
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * Format this code with GNU indent '-kr -i8 -pcs' options.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
3262306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
3362306a36Sopenharmony_ci * for more details.
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <linux/aperture.h>
3862306a36Sopenharmony_ci#include <linux/module.h>
3962306a36Sopenharmony_ci#include <linux/kernel.h>
4062306a36Sopenharmony_ci#include <linux/errno.h>
4162306a36Sopenharmony_ci#include <linux/string.h>
4262306a36Sopenharmony_ci#include <linux/mm.h>
4362306a36Sopenharmony_ci#include <linux/delay.h>
4462306a36Sopenharmony_ci#include <linux/fb.h>
4562306a36Sopenharmony_ci#include <linux/init.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
4862306a36Sopenharmony_ci#include <linux/zorro.h>
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci#ifdef CONFIG_PCI
5162306a36Sopenharmony_ci#include <linux/pci.h>
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci#ifdef CONFIG_AMIGA
5462306a36Sopenharmony_ci#include <asm/amigahw.h>
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include <video/vga.h>
5862306a36Sopenharmony_ci#include <video/cirrus.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/*****************************************************************
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * debugging and utility macros
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* disable runtime assertions? */
6762306a36Sopenharmony_ci/* #define CIRRUSFB_NDEBUG */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* debugging assertions */
7062306a36Sopenharmony_ci#ifndef CIRRUSFB_NDEBUG
7162306a36Sopenharmony_ci#define assert(expr) \
7262306a36Sopenharmony_ci	if (!(expr)) { \
7362306a36Sopenharmony_ci		printk("Assertion failed! %s,%s,%s,line=%d\n", \
7462306a36Sopenharmony_ci		#expr, __FILE__, __func__, __LINE__); \
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci#else
7762306a36Sopenharmony_ci#define assert(expr)
7862306a36Sopenharmony_ci#endif
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define MB_ (1024 * 1024)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*****************************************************************
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * chipset information
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* board types */
8962306a36Sopenharmony_cienum cirrus_board {
9062306a36Sopenharmony_ci	BT_NONE = 0,
9162306a36Sopenharmony_ci	BT_SD64,	/* GD5434 */
9262306a36Sopenharmony_ci	BT_PICCOLO,	/* GD5426 */
9362306a36Sopenharmony_ci	BT_PICASSO,	/* GD5426 or GD5428 */
9462306a36Sopenharmony_ci	BT_SPECTRUM,	/* GD5426 or GD5428 */
9562306a36Sopenharmony_ci	BT_PICASSO4,	/* GD5446 */
9662306a36Sopenharmony_ci	BT_ALPINE,	/* GD543x/4x */
9762306a36Sopenharmony_ci	BT_GD5480,
9862306a36Sopenharmony_ci	BT_LAGUNA,	/* GD5462/64 */
9962306a36Sopenharmony_ci	BT_LAGUNAB,	/* GD5465 */
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/*
10362306a36Sopenharmony_ci * per-board-type information, used for enumerating and abstracting
10462306a36Sopenharmony_ci * chip-specific information
10562306a36Sopenharmony_ci * NOTE: MUST be in the same order as enum cirrus_board in order to
10662306a36Sopenharmony_ci * use direct indexing on this array
10762306a36Sopenharmony_ci * NOTE: '__initdata' cannot be used as some of this info
10862306a36Sopenharmony_ci * is required at runtime.  Maybe separate into an init-only and
10962306a36Sopenharmony_ci * a run-time table?
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cistatic const struct cirrusfb_board_info_rec {
11262306a36Sopenharmony_ci	char *name;		/* ASCII name of chipset */
11362306a36Sopenharmony_ci	long maxclock[5];		/* maximum video clock */
11462306a36Sopenharmony_ci	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
11562306a36Sopenharmony_ci	bool init_sr07 : 1; /* init SR07 during init_vgachip() */
11662306a36Sopenharmony_ci	bool init_sr1f : 1; /* write SR1F during init_vgachip() */
11762306a36Sopenharmony_ci	/* construct bit 19 of screen start address */
11862306a36Sopenharmony_ci	bool scrn_start_bit19 : 1;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* initial SR07 value, then for each mode */
12162306a36Sopenharmony_ci	unsigned char sr07;
12262306a36Sopenharmony_ci	unsigned char sr07_1bpp;
12362306a36Sopenharmony_ci	unsigned char sr07_1bpp_mux;
12462306a36Sopenharmony_ci	unsigned char sr07_8bpp;
12562306a36Sopenharmony_ci	unsigned char sr07_8bpp_mux;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	unsigned char sr1f;	/* SR1F VGA initial register value */
12862306a36Sopenharmony_ci} cirrusfb_board_info[] = {
12962306a36Sopenharmony_ci	[BT_SD64] = {
13062306a36Sopenharmony_ci		.name			= "CL SD64",
13162306a36Sopenharmony_ci		.maxclock		= {
13262306a36Sopenharmony_ci			/* guess */
13362306a36Sopenharmony_ci			/* the SD64/P4 have a higher max. videoclock */
13462306a36Sopenharmony_ci			135100, 135100, 85500, 85500, 0
13562306a36Sopenharmony_ci		},
13662306a36Sopenharmony_ci		.init_sr07		= true,
13762306a36Sopenharmony_ci		.init_sr1f		= true,
13862306a36Sopenharmony_ci		.scrn_start_bit19	= true,
13962306a36Sopenharmony_ci		.sr07			= 0xF0,
14062306a36Sopenharmony_ci		.sr07_1bpp		= 0xF0,
14162306a36Sopenharmony_ci		.sr07_1bpp_mux		= 0xF6,
14262306a36Sopenharmony_ci		.sr07_8bpp		= 0xF1,
14362306a36Sopenharmony_ci		.sr07_8bpp_mux		= 0xF7,
14462306a36Sopenharmony_ci		.sr1f			= 0x1E
14562306a36Sopenharmony_ci	},
14662306a36Sopenharmony_ci	[BT_PICCOLO] = {
14762306a36Sopenharmony_ci		.name			= "CL Piccolo",
14862306a36Sopenharmony_ci		.maxclock		= {
14962306a36Sopenharmony_ci			/* guess */
15062306a36Sopenharmony_ci			90000, 90000, 90000, 90000, 90000
15162306a36Sopenharmony_ci		},
15262306a36Sopenharmony_ci		.init_sr07		= true,
15362306a36Sopenharmony_ci		.init_sr1f		= true,
15462306a36Sopenharmony_ci		.scrn_start_bit19	= false,
15562306a36Sopenharmony_ci		.sr07			= 0x80,
15662306a36Sopenharmony_ci		.sr07_1bpp		= 0x80,
15762306a36Sopenharmony_ci		.sr07_8bpp		= 0x81,
15862306a36Sopenharmony_ci		.sr1f			= 0x22
15962306a36Sopenharmony_ci	},
16062306a36Sopenharmony_ci	[BT_PICASSO] = {
16162306a36Sopenharmony_ci		.name			= "CL Picasso",
16262306a36Sopenharmony_ci		.maxclock		= {
16362306a36Sopenharmony_ci			/* guess */
16462306a36Sopenharmony_ci			90000, 90000, 90000, 90000, 90000
16562306a36Sopenharmony_ci		},
16662306a36Sopenharmony_ci		.init_sr07		= true,
16762306a36Sopenharmony_ci		.init_sr1f		= true,
16862306a36Sopenharmony_ci		.scrn_start_bit19	= false,
16962306a36Sopenharmony_ci		.sr07			= 0x20,
17062306a36Sopenharmony_ci		.sr07_1bpp		= 0x20,
17162306a36Sopenharmony_ci		.sr07_8bpp		= 0x21,
17262306a36Sopenharmony_ci		.sr1f			= 0x22
17362306a36Sopenharmony_ci	},
17462306a36Sopenharmony_ci	[BT_SPECTRUM] = {
17562306a36Sopenharmony_ci		.name			= "CL Spectrum",
17662306a36Sopenharmony_ci		.maxclock		= {
17762306a36Sopenharmony_ci			/* guess */
17862306a36Sopenharmony_ci			90000, 90000, 90000, 90000, 90000
17962306a36Sopenharmony_ci		},
18062306a36Sopenharmony_ci		.init_sr07		= true,
18162306a36Sopenharmony_ci		.init_sr1f		= true,
18262306a36Sopenharmony_ci		.scrn_start_bit19	= false,
18362306a36Sopenharmony_ci		.sr07			= 0x80,
18462306a36Sopenharmony_ci		.sr07_1bpp		= 0x80,
18562306a36Sopenharmony_ci		.sr07_8bpp		= 0x81,
18662306a36Sopenharmony_ci		.sr1f			= 0x22
18762306a36Sopenharmony_ci	},
18862306a36Sopenharmony_ci	[BT_PICASSO4] = {
18962306a36Sopenharmony_ci		.name			= "CL Picasso4",
19062306a36Sopenharmony_ci		.maxclock		= {
19162306a36Sopenharmony_ci			135100, 135100, 85500, 85500, 0
19262306a36Sopenharmony_ci		},
19362306a36Sopenharmony_ci		.init_sr07		= true,
19462306a36Sopenharmony_ci		.init_sr1f		= false,
19562306a36Sopenharmony_ci		.scrn_start_bit19	= true,
19662306a36Sopenharmony_ci		.sr07			= 0xA0,
19762306a36Sopenharmony_ci		.sr07_1bpp		= 0xA0,
19862306a36Sopenharmony_ci		.sr07_1bpp_mux		= 0xA6,
19962306a36Sopenharmony_ci		.sr07_8bpp		= 0xA1,
20062306a36Sopenharmony_ci		.sr07_8bpp_mux		= 0xA7,
20162306a36Sopenharmony_ci		.sr1f			= 0
20262306a36Sopenharmony_ci	},
20362306a36Sopenharmony_ci	[BT_ALPINE] = {
20462306a36Sopenharmony_ci		.name			= "CL Alpine",
20562306a36Sopenharmony_ci		.maxclock		= {
20662306a36Sopenharmony_ci			/* for the GD5430.  GD5446 can do more... */
20762306a36Sopenharmony_ci			85500, 85500, 50000, 28500, 0
20862306a36Sopenharmony_ci		},
20962306a36Sopenharmony_ci		.init_sr07		= true,
21062306a36Sopenharmony_ci		.init_sr1f		= true,
21162306a36Sopenharmony_ci		.scrn_start_bit19	= true,
21262306a36Sopenharmony_ci		.sr07			= 0xA0,
21362306a36Sopenharmony_ci		.sr07_1bpp		= 0xA0,
21462306a36Sopenharmony_ci		.sr07_1bpp_mux		= 0xA6,
21562306a36Sopenharmony_ci		.sr07_8bpp		= 0xA1,
21662306a36Sopenharmony_ci		.sr07_8bpp_mux		= 0xA7,
21762306a36Sopenharmony_ci		.sr1f			= 0x1C
21862306a36Sopenharmony_ci	},
21962306a36Sopenharmony_ci	[BT_GD5480] = {
22062306a36Sopenharmony_ci		.name			= "CL GD5480",
22162306a36Sopenharmony_ci		.maxclock		= {
22262306a36Sopenharmony_ci			135100, 200000, 200000, 135100, 135100
22362306a36Sopenharmony_ci		},
22462306a36Sopenharmony_ci		.init_sr07		= true,
22562306a36Sopenharmony_ci		.init_sr1f		= true,
22662306a36Sopenharmony_ci		.scrn_start_bit19	= true,
22762306a36Sopenharmony_ci		.sr07			= 0x10,
22862306a36Sopenharmony_ci		.sr07_1bpp		= 0x11,
22962306a36Sopenharmony_ci		.sr07_8bpp		= 0x11,
23062306a36Sopenharmony_ci		.sr1f			= 0x1C
23162306a36Sopenharmony_ci	},
23262306a36Sopenharmony_ci	[BT_LAGUNA] = {
23362306a36Sopenharmony_ci		.name			= "CL Laguna",
23462306a36Sopenharmony_ci		.maxclock		= {
23562306a36Sopenharmony_ci			/* taken from X11 code */
23662306a36Sopenharmony_ci			170000, 170000, 170000, 170000, 135100,
23762306a36Sopenharmony_ci		},
23862306a36Sopenharmony_ci		.init_sr07		= false,
23962306a36Sopenharmony_ci		.init_sr1f		= false,
24062306a36Sopenharmony_ci		.scrn_start_bit19	= true,
24162306a36Sopenharmony_ci	},
24262306a36Sopenharmony_ci	[BT_LAGUNAB] = {
24362306a36Sopenharmony_ci		.name			= "CL Laguna AGP",
24462306a36Sopenharmony_ci		.maxclock		= {
24562306a36Sopenharmony_ci			/* taken from X11 code */
24662306a36Sopenharmony_ci			170000, 250000, 170000, 170000, 135100,
24762306a36Sopenharmony_ci		},
24862306a36Sopenharmony_ci		.init_sr07		= false,
24962306a36Sopenharmony_ci		.init_sr1f		= false,
25062306a36Sopenharmony_ci		.scrn_start_bit19	= true,
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci#ifdef CONFIG_PCI
25562306a36Sopenharmony_ci#define CHIP(id, btype) \
25662306a36Sopenharmony_ci	{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic struct pci_device_id cirrusfb_pci_table[] = {
25962306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
26062306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64),
26162306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64),
26262306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
26362306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
26462306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
26562306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
26662306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
26762306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
26862306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
26962306a36Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/
27062306a36Sopenharmony_ci	{ 0, }
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
27362306a36Sopenharmony_ci#undef CHIP
27462306a36Sopenharmony_ci#endif /* CONFIG_PCI */
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
27762306a36Sopenharmony_cistruct zorrocl {
27862306a36Sopenharmony_ci	enum cirrus_board type;	/* Board type */
27962306a36Sopenharmony_ci	u32 regoffset;		/* Offset of registers in first Zorro device */
28062306a36Sopenharmony_ci	u32 ramsize;		/* Size of video RAM in first Zorro device */
28162306a36Sopenharmony_ci				/* If zero, use autoprobe on RAM device */
28262306a36Sopenharmony_ci	u32 ramoffset;		/* Offset of video RAM in first Zorro device */
28362306a36Sopenharmony_ci	zorro_id ramid;		/* Zorro ID of RAM device */
28462306a36Sopenharmony_ci	zorro_id ramid2;	/* Zorro ID of optional second RAM device */
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic const struct zorrocl zcl_sd64 = {
28862306a36Sopenharmony_ci	.type		= BT_SD64,
28962306a36Sopenharmony_ci	.ramid		= ZORRO_PROD_HELFRICH_SD64_RAM,
29062306a36Sopenharmony_ci};
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic const struct zorrocl zcl_piccolo = {
29362306a36Sopenharmony_ci	.type		= BT_PICCOLO,
29462306a36Sopenharmony_ci	.ramid		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic const struct zorrocl zcl_picasso = {
29862306a36Sopenharmony_ci	.type		= BT_PICASSO,
29962306a36Sopenharmony_ci	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic const struct zorrocl zcl_spectrum = {
30362306a36Sopenharmony_ci	.type		= BT_SPECTRUM,
30462306a36Sopenharmony_ci	.ramid		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic const struct zorrocl zcl_picasso4_z3 = {
30862306a36Sopenharmony_ci	.type		= BT_PICASSO4,
30962306a36Sopenharmony_ci	.regoffset	= 0x00600000,
31062306a36Sopenharmony_ci	.ramsize	= 4 * MB_,
31162306a36Sopenharmony_ci	.ramoffset	= 0x01000000,	/* 0x02000000 for 64 MiB boards */
31262306a36Sopenharmony_ci};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic const struct zorrocl zcl_picasso4_z2 = {
31562306a36Sopenharmony_ci	.type		= BT_PICASSO4,
31662306a36Sopenharmony_ci	.regoffset	= 0x10000,
31762306a36Sopenharmony_ci	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
31862306a36Sopenharmony_ci	.ramid2		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2,
31962306a36Sopenharmony_ci};
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic const struct zorro_device_id cirrusfb_zorro_table[] = {
32362306a36Sopenharmony_ci	{
32462306a36Sopenharmony_ci		.id		= ZORRO_PROD_HELFRICH_SD64_REG,
32562306a36Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_sd64,
32662306a36Sopenharmony_ci	}, {
32762306a36Sopenharmony_ci		.id		= ZORRO_PROD_HELFRICH_PICCOLO_REG,
32862306a36Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_piccolo,
32962306a36Sopenharmony_ci	}, {
33062306a36Sopenharmony_ci		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
33162306a36Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_picasso,
33262306a36Sopenharmony_ci	}, {
33362306a36Sopenharmony_ci		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
33462306a36Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_spectrum,
33562306a36Sopenharmony_ci	}, {
33662306a36Sopenharmony_ci		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
33762306a36Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_picasso4_z3,
33862306a36Sopenharmony_ci	}, {
33962306a36Sopenharmony_ci		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG,
34062306a36Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_picasso4_z2,
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci	{ 0 }
34362306a36Sopenharmony_ci};
34462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
34562306a36Sopenharmony_ci#endif /* CONFIG_ZORRO */
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
34862306a36Sopenharmony_cienum cirrusfb_dbg_reg_class {
34962306a36Sopenharmony_ci	CRT,
35062306a36Sopenharmony_ci	SEQ
35162306a36Sopenharmony_ci};
35262306a36Sopenharmony_ci#endif		/* CIRRUSFB_DEBUG */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/* info about board */
35562306a36Sopenharmony_cistruct cirrusfb_info {
35662306a36Sopenharmony_ci	u8 __iomem *regbase;
35762306a36Sopenharmony_ci	u8 __iomem *laguna_mmio;
35862306a36Sopenharmony_ci	enum cirrus_board btype;
35962306a36Sopenharmony_ci	unsigned char SFR;	/* Shadow of special function register */
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	int multiplexing;
36262306a36Sopenharmony_ci	int doubleVCLK;
36362306a36Sopenharmony_ci	int blank_mode;
36462306a36Sopenharmony_ci	u32 pseudo_palette[16];
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	void (*unmap)(struct fb_info *info);
36762306a36Sopenharmony_ci};
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic bool noaccel;
37062306a36Sopenharmony_cistatic char *mode_option = "640x480@60";
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/****************************************************************************/
37362306a36Sopenharmony_ci/**** BEGIN PROTOTYPES ******************************************************/
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/*--- Interface used by the world ------------------------------------------*/
37662306a36Sopenharmony_cistatic int cirrusfb_pan_display(struct fb_var_screeninfo *var,
37762306a36Sopenharmony_ci				struct fb_info *info);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci/*--- Internal routines ----------------------------------------------------*/
38062306a36Sopenharmony_cistatic void init_vgachip(struct fb_info *info);
38162306a36Sopenharmony_cistatic void switch_monitor(struct cirrusfb_info *cinfo, int on);
38262306a36Sopenharmony_cistatic void WGen(const struct cirrusfb_info *cinfo,
38362306a36Sopenharmony_ci		 int regnum, unsigned char val);
38462306a36Sopenharmony_cistatic unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
38562306a36Sopenharmony_cistatic void AttrOn(const struct cirrusfb_info *cinfo);
38662306a36Sopenharmony_cistatic void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
38762306a36Sopenharmony_cistatic void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
38862306a36Sopenharmony_cistatic void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
38962306a36Sopenharmony_cistatic void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
39062306a36Sopenharmony_ci		  unsigned char red, unsigned char green, unsigned char blue);
39162306a36Sopenharmony_ci#if 0
39262306a36Sopenharmony_cistatic void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
39362306a36Sopenharmony_ci		  unsigned char *red, unsigned char *green,
39462306a36Sopenharmony_ci		  unsigned char *blue);
39562306a36Sopenharmony_ci#endif
39662306a36Sopenharmony_cistatic void cirrusfb_WaitBLT(u8 __iomem *regbase);
39762306a36Sopenharmony_cistatic void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
39862306a36Sopenharmony_ci			    u_short curx, u_short cury,
39962306a36Sopenharmony_ci			    u_short destx, u_short desty,
40062306a36Sopenharmony_ci			    u_short width, u_short height,
40162306a36Sopenharmony_ci			    u_short line_length);
40262306a36Sopenharmony_cistatic void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
40362306a36Sopenharmony_ci			      u_short x, u_short y,
40462306a36Sopenharmony_ci			      u_short width, u_short height,
40562306a36Sopenharmony_ci			      u32 fg_color, u32 bg_color,
40662306a36Sopenharmony_ci			      u_short line_length, u_char blitmode);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void bestclock(long freq, int *nom, int *den, int *div);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
41162306a36Sopenharmony_cistatic void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
41262306a36Sopenharmony_cistatic void cirrusfb_dbg_print_regs(struct fb_info *info,
41362306a36Sopenharmony_ci				    caddr_t regbase,
41462306a36Sopenharmony_ci				    enum cirrusfb_dbg_reg_class reg_class, ...);
41562306a36Sopenharmony_ci#endif /* CIRRUSFB_DEBUG */
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/*** END   PROTOTYPES ********************************************************/
41862306a36Sopenharmony_ci/*****************************************************************************/
41962306a36Sopenharmony_ci/*** BEGIN Interface Used by the World ***************************************/
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic inline int is_laguna(const struct cirrusfb_info *cinfo)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int opencount;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/*--- Open /dev/fbx ---------------------------------------------------------*/
42962306a36Sopenharmony_cistatic int cirrusfb_open(struct fb_info *info, int user)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	if (opencount++ == 0)
43262306a36Sopenharmony_ci		switch_monitor(info->par, 1);
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/*--- Close /dev/fbx --------------------------------------------------------*/
43762306a36Sopenharmony_cistatic int cirrusfb_release(struct fb_info *info, int user)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	if (--opencount == 0)
44062306a36Sopenharmony_ci		switch_monitor(info->par, 0);
44162306a36Sopenharmony_ci	return 0;
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/**** END   Interface used by the World *************************************/
44562306a36Sopenharmony_ci/****************************************************************************/
44662306a36Sopenharmony_ci/**** BEGIN Hardware specific Routines **************************************/
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/* Check if the MCLK is not a better clock source */
44962306a36Sopenharmony_cistatic int cirrusfb_check_mclk(struct fb_info *info, long freq)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
45262306a36Sopenharmony_ci	long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Read MCLK value */
45562306a36Sopenharmony_ci	mclk = (14318 * mclk) >> 3;
45662306a36Sopenharmony_ci	dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* Determine if we should use MCLK instead of VCLK, and if so, what we
45962306a36Sopenharmony_ci	 * should divide it by to get VCLK
46062306a36Sopenharmony_ci	 */
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (abs(freq - mclk) < 250) {
46362306a36Sopenharmony_ci		dev_dbg(info->device, "Using VCLK = MCLK\n");
46462306a36Sopenharmony_ci		return 1;
46562306a36Sopenharmony_ci	} else if (abs(freq - (mclk / 2)) < 250) {
46662306a36Sopenharmony_ci		dev_dbg(info->device, "Using VCLK = MCLK/2\n");
46762306a36Sopenharmony_ci		return 2;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	return 0;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
47462306a36Sopenharmony_ci				   struct fb_info *info)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	long freq;
47762306a36Sopenharmony_ci	long maxclock;
47862306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
47962306a36Sopenharmony_ci	unsigned maxclockidx = var->bits_per_pixel >> 3;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/* convert from ps to kHz */
48262306a36Sopenharmony_ci	freq = PICOS2KHZ(var->pixclock ? : 1);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
48562306a36Sopenharmony_ci	cinfo->multiplexing = 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	/* If the frequency is greater than we can support, we might be able
48862306a36Sopenharmony_ci	 * to use multiplexing for the video mode */
48962306a36Sopenharmony_ci	if (freq > maxclock) {
49062306a36Sopenharmony_ci		var->pixclock = KHZ2PICOS(maxclock);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		while ((freq = PICOS2KHZ(var->pixclock)) > maxclock)
49362306a36Sopenharmony_ci			var->pixclock++;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci	dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/*
49862306a36Sopenharmony_ci	 * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
49962306a36Sopenharmony_ci	 * pixel clock
50062306a36Sopenharmony_ci	 */
50162306a36Sopenharmony_ci	if (var->bits_per_pixel == 8) {
50262306a36Sopenharmony_ci		switch (cinfo->btype) {
50362306a36Sopenharmony_ci		case BT_ALPINE:
50462306a36Sopenharmony_ci		case BT_SD64:
50562306a36Sopenharmony_ci		case BT_PICASSO4:
50662306a36Sopenharmony_ci			if (freq > 85500)
50762306a36Sopenharmony_ci				cinfo->multiplexing = 1;
50862306a36Sopenharmony_ci			break;
50962306a36Sopenharmony_ci		case BT_GD5480:
51062306a36Sopenharmony_ci			if (freq > 135100)
51162306a36Sopenharmony_ci				cinfo->multiplexing = 1;
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		default:
51562306a36Sopenharmony_ci			break;
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* If we have a 1MB 5434, we need to put ourselves in a mode where
52062306a36Sopenharmony_ci	 * the VCLK is double the pixel clock. */
52162306a36Sopenharmony_ci	cinfo->doubleVCLK = 0;
52262306a36Sopenharmony_ci	if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ &&
52362306a36Sopenharmony_ci	    var->bits_per_pixel == 16) {
52462306a36Sopenharmony_ci		cinfo->doubleVCLK = 1;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int cirrusfb_check_var(struct fb_var_screeninfo *var,
53162306a36Sopenharmony_ci			      struct fb_info *info)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	int yres;
53462306a36Sopenharmony_ci	/* memory size in pixels */
53562306a36Sopenharmony_ci	unsigned int pixels;
53662306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
53962306a36Sopenharmony_ci	case 1:
54062306a36Sopenharmony_ci		var->red.offset = 0;
54162306a36Sopenharmony_ci		var->red.length = 1;
54262306a36Sopenharmony_ci		var->green = var->red;
54362306a36Sopenharmony_ci		var->blue = var->red;
54462306a36Sopenharmony_ci		break;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	case 8:
54762306a36Sopenharmony_ci		var->red.offset = 0;
54862306a36Sopenharmony_ci		var->red.length = 8;
54962306a36Sopenharmony_ci		var->green = var->red;
55062306a36Sopenharmony_ci		var->blue = var->red;
55162306a36Sopenharmony_ci		break;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	case 16:
55462306a36Sopenharmony_ci		var->red.offset = 11;
55562306a36Sopenharmony_ci		var->green.offset = 5;
55662306a36Sopenharmony_ci		var->blue.offset = 0;
55762306a36Sopenharmony_ci		var->red.length = 5;
55862306a36Sopenharmony_ci		var->green.length = 6;
55962306a36Sopenharmony_ci		var->blue.length = 5;
56062306a36Sopenharmony_ci		break;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	case 24:
56362306a36Sopenharmony_ci		var->red.offset = 16;
56462306a36Sopenharmony_ci		var->green.offset = 8;
56562306a36Sopenharmony_ci		var->blue.offset = 0;
56662306a36Sopenharmony_ci		var->red.length = 8;
56762306a36Sopenharmony_ci		var->green.length = 8;
56862306a36Sopenharmony_ci		var->blue.length = 8;
56962306a36Sopenharmony_ci		break;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	default:
57262306a36Sopenharmony_ci		dev_dbg(info->device,
57362306a36Sopenharmony_ci			"Unsupported bpp size: %d\n", var->bits_per_pixel);
57462306a36Sopenharmony_ci		return -EINVAL;
57562306a36Sopenharmony_ci	}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	pixels = info->screen_size * 8 / var->bits_per_pixel;
57862306a36Sopenharmony_ci	if (var->xres_virtual < var->xres)
57962306a36Sopenharmony_ci		var->xres_virtual = var->xres;
58062306a36Sopenharmony_ci	/* use highest possible virtual resolution */
58162306a36Sopenharmony_ci	if (var->yres_virtual == -1) {
58262306a36Sopenharmony_ci		var->yres_virtual = pixels / var->xres_virtual;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		dev_info(info->device,
58562306a36Sopenharmony_ci			 "virtual resolution set to maximum of %dx%d\n",
58662306a36Sopenharmony_ci			 var->xres_virtual, var->yres_virtual);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	if (var->yres_virtual < var->yres)
58962306a36Sopenharmony_ci		var->yres_virtual = var->yres;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (var->xres_virtual * var->yres_virtual > pixels) {
59262306a36Sopenharmony_ci		dev_err(info->device, "mode %dx%dx%d rejected... "
59362306a36Sopenharmony_ci		      "virtual resolution too high to fit into video memory!\n",
59462306a36Sopenharmony_ci			var->xres_virtual, var->yres_virtual,
59562306a36Sopenharmony_ci			var->bits_per_pixel);
59662306a36Sopenharmony_ci		return -EINVAL;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* truncate xoffset and yoffset to maximum if too high */
60062306a36Sopenharmony_ci	if (var->xoffset > var->xres_virtual - var->xres)
60162306a36Sopenharmony_ci		var->xoffset = var->xres_virtual - var->xres - 1;
60262306a36Sopenharmony_ci	if (var->yoffset > var->yres_virtual - var->yres)
60362306a36Sopenharmony_ci		var->yoffset = var->yres_virtual - var->yres - 1;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	var->red.msb_right =
60662306a36Sopenharmony_ci	    var->green.msb_right =
60762306a36Sopenharmony_ci	    var->blue.msb_right =
60862306a36Sopenharmony_ci	    var->transp.offset =
60962306a36Sopenharmony_ci	    var->transp.length =
61062306a36Sopenharmony_ci	    var->transp.msb_right = 0;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	yres = var->yres;
61362306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE)
61462306a36Sopenharmony_ci		yres *= 2;
61562306a36Sopenharmony_ci	else if (var->vmode & FB_VMODE_INTERLACED)
61662306a36Sopenharmony_ci		yres = (yres + 1) / 2;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (yres >= 1280) {
61962306a36Sopenharmony_ci		dev_err(info->device, "ERROR: VerticalTotal >= 1280; "
62062306a36Sopenharmony_ci			"special treatment required! (TODO)\n");
62162306a36Sopenharmony_ci		return -EINVAL;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (cirrusfb_check_pixclock(var, info))
62562306a36Sopenharmony_ci		return -EINVAL;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (!is_laguna(cinfo))
62862306a36Sopenharmony_ci		var->accel_flags = FB_ACCELF_TEXT;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return 0;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
63662306a36Sopenharmony_ci	unsigned char old1f, old1e;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	assert(cinfo != NULL);
63962306a36Sopenharmony_ci	old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (div) {
64262306a36Sopenharmony_ci		dev_dbg(info->device, "Set %s as pixclock source.\n",
64362306a36Sopenharmony_ci			(div == 2) ? "MCLK/2" : "MCLK");
64462306a36Sopenharmony_ci		old1f |= 0x40;
64562306a36Sopenharmony_ci		old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
64662306a36Sopenharmony_ci		if (div == 2)
64762306a36Sopenharmony_ci			old1e |= 1;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci/*************************************************************************
65562306a36Sopenharmony_ci	cirrusfb_set_par_foo()
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	actually writes the values for a new video mode into the hardware,
65862306a36Sopenharmony_ci**************************************************************************/
65962306a36Sopenharmony_cistatic int cirrusfb_set_par_foo(struct fb_info *info)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
66262306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &info->var;
66362306a36Sopenharmony_ci	u8 __iomem *regbase = cinfo->regbase;
66462306a36Sopenharmony_ci	unsigned char tmp;
66562306a36Sopenharmony_ci	int pitch;
66662306a36Sopenharmony_ci	const struct cirrusfb_board_info_rec *bi;
66762306a36Sopenharmony_ci	int hdispend, hsyncstart, hsyncend, htotal;
66862306a36Sopenharmony_ci	int yres, vdispend, vsyncstart, vsyncend, vtotal;
66962306a36Sopenharmony_ci	long freq;
67062306a36Sopenharmony_ci	int nom, den, div;
67162306a36Sopenharmony_ci	unsigned int control = 0, format = 0, threshold = 0;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
67462306a36Sopenharmony_ci	       var->xres, var->yres, var->bits_per_pixel);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	switch (var->bits_per_pixel) {
67762306a36Sopenharmony_ci	case 1:
67862306a36Sopenharmony_ci		info->fix.line_length = var->xres_virtual / 8;
67962306a36Sopenharmony_ci		info->fix.visual = FB_VISUAL_MONO10;
68062306a36Sopenharmony_ci		break;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	case 8:
68362306a36Sopenharmony_ci		info->fix.line_length = var->xres_virtual;
68462306a36Sopenharmony_ci		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
68562306a36Sopenharmony_ci		break;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	case 16:
68862306a36Sopenharmony_ci	case 24:
68962306a36Sopenharmony_ci		info->fix.line_length = var->xres_virtual *
69062306a36Sopenharmony_ci					var->bits_per_pixel >> 3;
69162306a36Sopenharmony_ci		info->fix.visual = FB_VISUAL_TRUECOLOR;
69262306a36Sopenharmony_ci		break;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	info->fix.type = FB_TYPE_PACKED_PIXELS;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	init_vgachip(info);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	bi = &cirrusfb_board_info[cinfo->btype];
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	hsyncstart = var->xres + var->right_margin;
70162306a36Sopenharmony_ci	hsyncend = hsyncstart + var->hsync_len;
70262306a36Sopenharmony_ci	htotal = (hsyncend + var->left_margin) / 8;
70362306a36Sopenharmony_ci	hdispend = var->xres / 8;
70462306a36Sopenharmony_ci	hsyncstart = hsyncstart / 8;
70562306a36Sopenharmony_ci	hsyncend = hsyncend / 8;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	vdispend = var->yres;
70862306a36Sopenharmony_ci	vsyncstart = vdispend + var->lower_margin;
70962306a36Sopenharmony_ci	vsyncend = vsyncstart + var->vsync_len;
71062306a36Sopenharmony_ci	vtotal = vsyncend + var->upper_margin;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE) {
71362306a36Sopenharmony_ci		vdispend *= 2;
71462306a36Sopenharmony_ci		vsyncstart *= 2;
71562306a36Sopenharmony_ci		vsyncend *= 2;
71662306a36Sopenharmony_ci		vtotal *= 2;
71762306a36Sopenharmony_ci	} else if (var->vmode & FB_VMODE_INTERLACED) {
71862306a36Sopenharmony_ci		vdispend = (vdispend + 1) / 2;
71962306a36Sopenharmony_ci		vsyncstart = (vsyncstart + 1) / 2;
72062306a36Sopenharmony_ci		vsyncend = (vsyncend + 1) / 2;
72162306a36Sopenharmony_ci		vtotal = (vtotal + 1) / 2;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci	yres = vdispend;
72462306a36Sopenharmony_ci	if (yres >= 1024) {
72562306a36Sopenharmony_ci		vtotal /= 2;
72662306a36Sopenharmony_ci		vsyncstart /= 2;
72762306a36Sopenharmony_ci		vsyncend /= 2;
72862306a36Sopenharmony_ci		vdispend /= 2;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	vdispend -= 1;
73262306a36Sopenharmony_ci	vsyncstart -= 1;
73362306a36Sopenharmony_ci	vsyncend -= 1;
73462306a36Sopenharmony_ci	vtotal -= 2;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (cinfo->multiplexing) {
73762306a36Sopenharmony_ci		htotal /= 2;
73862306a36Sopenharmony_ci		hsyncstart /= 2;
73962306a36Sopenharmony_ci		hsyncend /= 2;
74062306a36Sopenharmony_ci		hdispend /= 2;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	htotal -= 5;
74462306a36Sopenharmony_ci	hdispend -= 1;
74562306a36Sopenharmony_ci	hsyncstart += 1;
74662306a36Sopenharmony_ci	hsyncend += 1;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
74962306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/* if debugging is enabled, all parameters get output before writing */
75262306a36Sopenharmony_ci	dev_dbg(info->device, "CRT0: %d\n", htotal);
75362306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	dev_dbg(info->device, "CRT1: %d\n", hdispend);
75662306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	dev_dbg(info->device, "CRT2: %d\n", var->xres / 8);
75962306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	/*  + 128: Compatible read */
76262306a36Sopenharmony_ci	dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32);
76362306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
76462306a36Sopenharmony_ci		 128 + ((htotal + 5) % 32));
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	dev_dbg(info->device, "CRT4: %d\n", hsyncstart);
76762306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	tmp = hsyncend % 32;
77062306a36Sopenharmony_ci	if ((htotal + 5) & 32)
77162306a36Sopenharmony_ci		tmp += 128;
77262306a36Sopenharmony_ci	dev_dbg(info->device, "CRT5: %d\n", tmp);
77362306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff);
77662306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	tmp = 16;		/* LineCompare bit #9 */
77962306a36Sopenharmony_ci	if (vtotal & 256)
78062306a36Sopenharmony_ci		tmp |= 1;
78162306a36Sopenharmony_ci	if (vdispend & 256)
78262306a36Sopenharmony_ci		tmp |= 2;
78362306a36Sopenharmony_ci	if (vsyncstart & 256)
78462306a36Sopenharmony_ci		tmp |= 4;
78562306a36Sopenharmony_ci	if ((vdispend + 1) & 256)
78662306a36Sopenharmony_ci		tmp |= 8;
78762306a36Sopenharmony_ci	if (vtotal & 512)
78862306a36Sopenharmony_ci		tmp |= 32;
78962306a36Sopenharmony_ci	if (vdispend & 512)
79062306a36Sopenharmony_ci		tmp |= 64;
79162306a36Sopenharmony_ci	if (vsyncstart & 512)
79262306a36Sopenharmony_ci		tmp |= 128;
79362306a36Sopenharmony_ci	dev_dbg(info->device, "CRT7: %d\n", tmp);
79462306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	tmp = 0x40;		/* LineCompare bit #8 */
79762306a36Sopenharmony_ci	if ((vdispend + 1) & 512)
79862306a36Sopenharmony_ci		tmp |= 0x20;
79962306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE)
80062306a36Sopenharmony_ci		tmp |= 0x80;
80162306a36Sopenharmony_ci	dev_dbg(info->device, "CRT9: %d\n", tmp);
80262306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff);
80562306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16);
80862306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff);
81162306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff);
81462306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff);
81762306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	dev_dbg(info->device, "CRT18: 0xff\n");
82062306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	tmp = 0;
82362306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED)
82462306a36Sopenharmony_ci		tmp |= 1;
82562306a36Sopenharmony_ci	if ((htotal + 5) & 64)
82662306a36Sopenharmony_ci		tmp |= 16;
82762306a36Sopenharmony_ci	if ((htotal + 5) & 128)
82862306a36Sopenharmony_ci		tmp |= 32;
82962306a36Sopenharmony_ci	if (vtotal & 256)
83062306a36Sopenharmony_ci		tmp |= 64;
83162306a36Sopenharmony_ci	if (vtotal & 512)
83262306a36Sopenharmony_ci		tmp |= 128;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	dev_dbg(info->device, "CRT1a: %d\n", tmp);
83562306a36Sopenharmony_ci	vga_wcrt(regbase, CL_CRT1A, tmp);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	freq = PICOS2KHZ(var->pixclock);
83862306a36Sopenharmony_ci	if (var->bits_per_pixel == 24)
83962306a36Sopenharmony_ci		if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
84062306a36Sopenharmony_ci			freq *= 3;
84162306a36Sopenharmony_ci	if (cinfo->multiplexing)
84262306a36Sopenharmony_ci		freq /= 2;
84362306a36Sopenharmony_ci	if (cinfo->doubleVCLK)
84462306a36Sopenharmony_ci		freq *= 2;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	bestclock(freq, &nom, &den, &div);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	dev_dbg(info->device, "VCLK freq: %ld kHz  nom: %d  den: %d  div: %d\n",
84962306a36Sopenharmony_ci		freq, nom, den, div);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* set VCLK0 */
85262306a36Sopenharmony_ci	/* hardware RefClock: 14.31818 MHz */
85362306a36Sopenharmony_ci	/* formula: VClk = (OSC * N) / (D * (1+P)) */
85462306a36Sopenharmony_ci	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 ||
85762306a36Sopenharmony_ci	    cinfo->btype == BT_SD64) {
85862306a36Sopenharmony_ci		/* if freq is close to mclk or mclk/2 select mclk
85962306a36Sopenharmony_ci		 * as clock source
86062306a36Sopenharmony_ci		 */
86162306a36Sopenharmony_ci		int divMCLK = cirrusfb_check_mclk(info, freq);
86262306a36Sopenharmony_ci		if (divMCLK)
86362306a36Sopenharmony_ci			nom = 0;
86462306a36Sopenharmony_ci		cirrusfb_set_mclk_as_source(info, divMCLK);
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci	if (is_laguna(cinfo)) {
86762306a36Sopenharmony_ci		long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
86862306a36Sopenharmony_ci		unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
86962306a36Sopenharmony_ci		unsigned short tile_control;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		if (cinfo->btype == BT_LAGUNAB) {
87262306a36Sopenharmony_ci			tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
87362306a36Sopenharmony_ci			tile_control &= ~0x80;
87462306a36Sopenharmony_ci			fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
87562306a36Sopenharmony_ci		}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci		fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
87862306a36Sopenharmony_ci		fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
87962306a36Sopenharmony_ci		control = fb_readw(cinfo->laguna_mmio + 0x402);
88062306a36Sopenharmony_ci		threshold = fb_readw(cinfo->laguna_mmio + 0xea);
88162306a36Sopenharmony_ci		control &= ~0x6800;
88262306a36Sopenharmony_ci		format = 0;
88362306a36Sopenharmony_ci		threshold &= 0xffc0 & 0x3fbf;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci	if (nom) {
88662306a36Sopenharmony_ci		tmp = den << 1;
88762306a36Sopenharmony_ci		if (div != 0)
88862306a36Sopenharmony_ci			tmp |= 1;
88962306a36Sopenharmony_ci		/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
89062306a36Sopenharmony_ci		if ((cinfo->btype == BT_SD64) ||
89162306a36Sopenharmony_ci		    (cinfo->btype == BT_ALPINE) ||
89262306a36Sopenharmony_ci		    (cinfo->btype == BT_GD5480))
89362306a36Sopenharmony_ci			tmp |= 0x80;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		/* Laguna chipset has reversed clock registers */
89662306a36Sopenharmony_ci		if (is_laguna(cinfo)) {
89762306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRE, tmp);
89862306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR1E, nom);
89962306a36Sopenharmony_ci		} else {
90062306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRE, nom);
90162306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR1E, tmp);
90262306a36Sopenharmony_ci		}
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (yres >= 1024)
90662306a36Sopenharmony_ci		/* 1280x1024 */
90762306a36Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
90862306a36Sopenharmony_ci	else
90962306a36Sopenharmony_ci		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
91062306a36Sopenharmony_ci		 * address wrap, no compat. */
91162306a36Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	/* don't know if it would hurt to also program this if no interlaced */
91462306a36Sopenharmony_ci	/* mode is used, but I feel better this way.. :-) */
91562306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED)
91662306a36Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);
91762306a36Sopenharmony_ci	else
91862306a36Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* adjust horizontal/vertical sync type (low/high), use VCLK3 */
92162306a36Sopenharmony_ci	/* enable display memory & CRTC I/O address for color mode */
92262306a36Sopenharmony_ci	tmp = 0x03 | 0xc;
92362306a36Sopenharmony_ci	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
92462306a36Sopenharmony_ci		tmp |= 0x40;
92562306a36Sopenharmony_ci	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
92662306a36Sopenharmony_ci		tmp |= 0x80;
92762306a36Sopenharmony_ci	WGen(cinfo, VGA_MIS_W, tmp);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* text cursor on and start line */
93062306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
93162306a36Sopenharmony_ci	/* text cursor end line */
93262306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/******************************************************
93562306a36Sopenharmony_ci	 *
93662306a36Sopenharmony_ci	 * 1 bpp
93762306a36Sopenharmony_ci	 *
93862306a36Sopenharmony_ci	 */
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	/* programming for different color depths */
94162306a36Sopenharmony_ci	if (var->bits_per_pixel == 1) {
94262306a36Sopenharmony_ci		dev_dbg(info->device, "preparing for 1 bit deep display\n");
94362306a36Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 0);	/* mode register */
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		/* SR07 */
94662306a36Sopenharmony_ci		switch (cinfo->btype) {
94762306a36Sopenharmony_ci		case BT_SD64:
94862306a36Sopenharmony_ci		case BT_PICCOLO:
94962306a36Sopenharmony_ci		case BT_PICASSO:
95062306a36Sopenharmony_ci		case BT_SPECTRUM:
95162306a36Sopenharmony_ci		case BT_PICASSO4:
95262306a36Sopenharmony_ci		case BT_ALPINE:
95362306a36Sopenharmony_ci		case BT_GD5480:
95462306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
95562306a36Sopenharmony_ci				 cinfo->multiplexing ?
95662306a36Sopenharmony_ci					bi->sr07_1bpp_mux : bi->sr07_1bpp);
95762306a36Sopenharmony_ci			break;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci		case BT_LAGUNA:
96062306a36Sopenharmony_ci		case BT_LAGUNAB:
96162306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
96262306a36Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) & ~0x01);
96362306a36Sopenharmony_ci			break;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		default:
96662306a36Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
96762306a36Sopenharmony_ci			break;
96862306a36Sopenharmony_ci		}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci		/* Extended Sequencer Mode */
97162306a36Sopenharmony_ci		switch (cinfo->btype) {
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		case BT_PICCOLO:
97462306a36Sopenharmony_ci		case BT_SPECTRUM:
97562306a36Sopenharmony_ci			/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
97662306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
97762306a36Sopenharmony_ci			break;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		case BT_PICASSO:
98062306a36Sopenharmony_ci			/* ## vorher d0 avoid FIFO underruns..? */
98162306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xd0);
98262306a36Sopenharmony_ci			break;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci		case BT_SD64:
98562306a36Sopenharmony_ci		case BT_PICASSO4:
98662306a36Sopenharmony_ci		case BT_ALPINE:
98762306a36Sopenharmony_ci		case BT_GD5480:
98862306a36Sopenharmony_ci		case BT_LAGUNA:
98962306a36Sopenharmony_ci		case BT_LAGUNAB:
99062306a36Sopenharmony_ci			/* do nothing */
99162306a36Sopenharmony_ci			break;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		default:
99462306a36Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
99562306a36Sopenharmony_ci			break;
99662306a36Sopenharmony_ci		}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		/* pixel mask: pass-through for first plane */
99962306a36Sopenharmony_ci		WGen(cinfo, VGA_PEL_MSK, 0x01);
100062306a36Sopenharmony_ci		if (cinfo->multiplexing)
100162306a36Sopenharmony_ci			/* hidden dac reg: 1280x1024 */
100262306a36Sopenharmony_ci			WHDR(cinfo, 0x4a);
100362306a36Sopenharmony_ci		else
100462306a36Sopenharmony_ci			/* hidden dac: nothing */
100562306a36Sopenharmony_ci			WHDR(cinfo, 0);
100662306a36Sopenharmony_ci		/* memory mode: odd/even, ext. memory */
100762306a36Sopenharmony_ci		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
100862306a36Sopenharmony_ci		/* plane mask: only write to first plane */
100962306a36Sopenharmony_ci		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
101062306a36Sopenharmony_ci	}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/******************************************************
101362306a36Sopenharmony_ci	 *
101462306a36Sopenharmony_ci	 * 8 bpp
101562306a36Sopenharmony_ci	 *
101662306a36Sopenharmony_ci	 */
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	else if (var->bits_per_pixel == 8) {
101962306a36Sopenharmony_ci		dev_dbg(info->device, "preparing for 8 bit deep display\n");
102062306a36Sopenharmony_ci		switch (cinfo->btype) {
102162306a36Sopenharmony_ci		case BT_SD64:
102262306a36Sopenharmony_ci		case BT_PICCOLO:
102362306a36Sopenharmony_ci		case BT_PICASSO:
102462306a36Sopenharmony_ci		case BT_SPECTRUM:
102562306a36Sopenharmony_ci		case BT_PICASSO4:
102662306a36Sopenharmony_ci		case BT_ALPINE:
102762306a36Sopenharmony_ci		case BT_GD5480:
102862306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
102962306a36Sopenharmony_ci				  cinfo->multiplexing ?
103062306a36Sopenharmony_ci					bi->sr07_8bpp_mux : bi->sr07_8bpp);
103162306a36Sopenharmony_ci			break;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci		case BT_LAGUNA:
103462306a36Sopenharmony_ci		case BT_LAGUNAB:
103562306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
103662306a36Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) | 0x01);
103762306a36Sopenharmony_ci			threshold |= 0x10;
103862306a36Sopenharmony_ci			break;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci		default:
104162306a36Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
104262306a36Sopenharmony_ci			break;
104362306a36Sopenharmony_ci		}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		switch (cinfo->btype) {
104662306a36Sopenharmony_ci		case BT_PICCOLO:
104762306a36Sopenharmony_ci		case BT_PICASSO:
104862306a36Sopenharmony_ci		case BT_SPECTRUM:
104962306a36Sopenharmony_ci			/* Fast Page-Mode writes */
105062306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
105162306a36Sopenharmony_ci			break;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		case BT_PICASSO4:
105462306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
105562306a36Sopenharmony_ci			/* ### INCOMPLETE!! */
105662306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb8);
105762306a36Sopenharmony_ci#endif
105862306a36Sopenharmony_ci		case BT_ALPINE:
105962306a36Sopenharmony_ci		case BT_SD64:
106062306a36Sopenharmony_ci		case BT_GD5480:
106162306a36Sopenharmony_ci		case BT_LAGUNA:
106262306a36Sopenharmony_ci		case BT_LAGUNAB:
106362306a36Sopenharmony_ci			/* do nothing */
106462306a36Sopenharmony_ci			break;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci		default:
106762306a36Sopenharmony_ci			dev_warn(info->device, "unknown board\n");
106862306a36Sopenharmony_ci			break;
106962306a36Sopenharmony_ci		}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci		/* mode register: 256 color mode */
107262306a36Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 64);
107362306a36Sopenharmony_ci		if (cinfo->multiplexing)
107462306a36Sopenharmony_ci			/* hidden dac reg: 1280x1024 */
107562306a36Sopenharmony_ci			WHDR(cinfo, 0x4a);
107662306a36Sopenharmony_ci		else
107762306a36Sopenharmony_ci			/* hidden dac: nothing */
107862306a36Sopenharmony_ci			WHDR(cinfo, 0);
107962306a36Sopenharmony_ci	}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	/******************************************************
108262306a36Sopenharmony_ci	 *
108362306a36Sopenharmony_ci	 * 16 bpp
108462306a36Sopenharmony_ci	 *
108562306a36Sopenharmony_ci	 */
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	else if (var->bits_per_pixel == 16) {
108862306a36Sopenharmony_ci		dev_dbg(info->device, "preparing for 16 bit deep display\n");
108962306a36Sopenharmony_ci		switch (cinfo->btype) {
109062306a36Sopenharmony_ci		case BT_PICCOLO:
109162306a36Sopenharmony_ci		case BT_SPECTRUM:
109262306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x87);
109362306a36Sopenharmony_ci			/* Fast Page-Mode writes */
109462306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
109562306a36Sopenharmony_ci			break;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		case BT_PICASSO:
109862306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x27);
109962306a36Sopenharmony_ci			/* Fast Page-Mode writes */
110062306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
110162306a36Sopenharmony_ci			break;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		case BT_SD64:
110462306a36Sopenharmony_ci		case BT_PICASSO4:
110562306a36Sopenharmony_ci		case BT_ALPINE:
110662306a36Sopenharmony_ci			/* Extended Sequencer Mode: 256c col. mode */
110762306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
110862306a36Sopenharmony_ci					cinfo->doubleVCLK ? 0xa3 : 0xa7);
110962306a36Sopenharmony_ci			break;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci		case BT_GD5480:
111262306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x17);
111362306a36Sopenharmony_ci			/* We already set SRF and SR1F */
111462306a36Sopenharmony_ci			break;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci		case BT_LAGUNA:
111762306a36Sopenharmony_ci		case BT_LAGUNAB:
111862306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
111962306a36Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) & ~0x01);
112062306a36Sopenharmony_ci			control |= 0x2000;
112162306a36Sopenharmony_ci			format |= 0x1400;
112262306a36Sopenharmony_ci			threshold |= 0x10;
112362306a36Sopenharmony_ci			break;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci		default:
112662306a36Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
112762306a36Sopenharmony_ci			break;
112862306a36Sopenharmony_ci		}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci		/* mode register: 256 color mode */
113162306a36Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 64);
113262306a36Sopenharmony_ci#ifdef CONFIG_PCI
113362306a36Sopenharmony_ci		WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
113462306a36Sopenharmony_ci#elif defined(CONFIG_ZORRO)
113562306a36Sopenharmony_ci		/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
113662306a36Sopenharmony_ci		WHDR(cinfo, 0xa0);	/* hidden dac reg: nothing special */
113762306a36Sopenharmony_ci#endif
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/******************************************************
114162306a36Sopenharmony_ci	 *
114262306a36Sopenharmony_ci	 * 24 bpp
114362306a36Sopenharmony_ci	 *
114462306a36Sopenharmony_ci	 */
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	else if (var->bits_per_pixel == 24) {
114762306a36Sopenharmony_ci		dev_dbg(info->device, "preparing for 24 bit deep display\n");
114862306a36Sopenharmony_ci		switch (cinfo->btype) {
114962306a36Sopenharmony_ci		case BT_PICCOLO:
115062306a36Sopenharmony_ci		case BT_SPECTRUM:
115162306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x85);
115262306a36Sopenharmony_ci			/* Fast Page-Mode writes */
115362306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
115462306a36Sopenharmony_ci			break;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		case BT_PICASSO:
115762306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x25);
115862306a36Sopenharmony_ci			/* Fast Page-Mode writes */
115962306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
116062306a36Sopenharmony_ci			break;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci		case BT_SD64:
116362306a36Sopenharmony_ci		case BT_PICASSO4:
116462306a36Sopenharmony_ci		case BT_ALPINE:
116562306a36Sopenharmony_ci			/* Extended Sequencer Mode: 256c col. mode */
116662306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0xa5);
116762306a36Sopenharmony_ci			break;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		case BT_GD5480:
117062306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x15);
117162306a36Sopenharmony_ci			/* We already set SRF and SR1F */
117262306a36Sopenharmony_ci			break;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		case BT_LAGUNA:
117562306a36Sopenharmony_ci		case BT_LAGUNAB:
117662306a36Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
117762306a36Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) & ~0x01);
117862306a36Sopenharmony_ci			control |= 0x4000;
117962306a36Sopenharmony_ci			format |= 0x2400;
118062306a36Sopenharmony_ci			threshold |= 0x20;
118162306a36Sopenharmony_ci			break;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		default:
118462306a36Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
118562306a36Sopenharmony_ci			break;
118662306a36Sopenharmony_ci		}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		/* mode register: 256 color mode */
118962306a36Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 64);
119062306a36Sopenharmony_ci		/* hidden dac reg: 8-8-8 mode (24 or 32) */
119162306a36Sopenharmony_ci		WHDR(cinfo, 0xc5);
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/******************************************************
119562306a36Sopenharmony_ci	 *
119662306a36Sopenharmony_ci	 * unknown/unsupported bpp
119762306a36Sopenharmony_ci	 *
119862306a36Sopenharmony_ci	 */
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	else
120162306a36Sopenharmony_ci		dev_err(info->device,
120262306a36Sopenharmony_ci			"What's this? requested color depth == %d.\n",
120362306a36Sopenharmony_ci			var->bits_per_pixel);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	pitch = info->fix.line_length >> 3;
120662306a36Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
120762306a36Sopenharmony_ci	tmp = 0x22;
120862306a36Sopenharmony_ci	if (pitch & 0x100)
120962306a36Sopenharmony_ci		tmp |= 0x10;	/* offset overflow bit */
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/* screen start addr #16-18, fastpagemode cycles */
121262306a36Sopenharmony_ci	vga_wcrt(regbase, CL_CRT1B, tmp);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/* screen start address bit 19 */
121562306a36Sopenharmony_ci	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
121662306a36Sopenharmony_ci		vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	if (is_laguna(cinfo)) {
121962306a36Sopenharmony_ci		tmp = 0;
122062306a36Sopenharmony_ci		if ((htotal + 5) & 256)
122162306a36Sopenharmony_ci			tmp |= 128;
122262306a36Sopenharmony_ci		if (hdispend & 256)
122362306a36Sopenharmony_ci			tmp |= 64;
122462306a36Sopenharmony_ci		if (hsyncstart & 256)
122562306a36Sopenharmony_ci			tmp |= 48;
122662306a36Sopenharmony_ci		if (vtotal & 1024)
122762306a36Sopenharmony_ci			tmp |= 8;
122862306a36Sopenharmony_ci		if (vdispend & 1024)
122962306a36Sopenharmony_ci			tmp |= 4;
123062306a36Sopenharmony_ci		if (vsyncstart & 1024)
123162306a36Sopenharmony_ci			tmp |= 3;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci		vga_wcrt(regbase, CL_CRT1E, tmp);
123462306a36Sopenharmony_ci		dev_dbg(info->device, "CRT1e: %d\n", tmp);
123562306a36Sopenharmony_ci	}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	/* pixel panning */
123862306a36Sopenharmony_ci	vga_wattr(regbase, CL_AR33, 0);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	/* [ EGS: SetOffset(); ] */
124162306a36Sopenharmony_ci	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
124262306a36Sopenharmony_ci	AttrOn(cinfo);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (is_laguna(cinfo)) {
124562306a36Sopenharmony_ci		/* no tiles */
124662306a36Sopenharmony_ci		fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
124762306a36Sopenharmony_ci		fb_writew(format, cinfo->laguna_mmio + 0xc0);
124862306a36Sopenharmony_ci		fb_writew(threshold, cinfo->laguna_mmio + 0xea);
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci	/* finally, turn on everything - turn off "FullBandwidth" bit */
125162306a36Sopenharmony_ci	/* also, set "DotClock%2" bit where requested */
125262306a36Sopenharmony_ci	tmp = 0x01;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
125562306a36Sopenharmony_ci    if (var->vmode & FB_VMODE_CLOCK_HALVE)
125662306a36Sopenharmony_ci	tmp |= 0x08;
125762306a36Sopenharmony_ci*/
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
126062306a36Sopenharmony_ci	dev_dbg(info->device, "CL_SEQR1: %d\n", tmp);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
126362306a36Sopenharmony_ci	cirrusfb_dbg_reg_dump(info, NULL);
126462306a36Sopenharmony_ci#endif
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	return 0;
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci/* for some reason incomprehensible to me, cirrusfb requires that you write
127062306a36Sopenharmony_ci * the registers twice for the settings to take..grr. -dte */
127162306a36Sopenharmony_cistatic int cirrusfb_set_par(struct fb_info *info)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	cirrusfb_set_par_foo(info);
127462306a36Sopenharmony_ci	return cirrusfb_set_par_foo(info);
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
127862306a36Sopenharmony_ci			      unsigned blue, unsigned transp,
127962306a36Sopenharmony_ci			      struct fb_info *info)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	if (regno > 255)
128462306a36Sopenharmony_ci		return -EINVAL;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
128762306a36Sopenharmony_ci		u32 v;
128862306a36Sopenharmony_ci		red >>= (16 - info->var.red.length);
128962306a36Sopenharmony_ci		green >>= (16 - info->var.green.length);
129062306a36Sopenharmony_ci		blue >>= (16 - info->var.blue.length);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci		if (regno >= 16)
129362306a36Sopenharmony_ci			return 1;
129462306a36Sopenharmony_ci		v = (red << info->var.red.offset) |
129562306a36Sopenharmony_ci		    (green << info->var.green.offset) |
129662306a36Sopenharmony_ci		    (blue << info->var.blue.offset);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci		cinfo->pseudo_palette[regno] = v;
129962306a36Sopenharmony_ci		return 0;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (info->var.bits_per_pixel == 8)
130362306a36Sopenharmony_ci		WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return 0;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci/*************************************************************************
131062306a36Sopenharmony_ci	cirrusfb_pan_display()
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	performs display panning - provided hardware permits this
131362306a36Sopenharmony_ci**************************************************************************/
131462306a36Sopenharmony_cistatic int cirrusfb_pan_display(struct fb_var_screeninfo *var,
131562306a36Sopenharmony_ci				struct fb_info *info)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	int xoffset;
131862306a36Sopenharmony_ci	unsigned long base;
131962306a36Sopenharmony_ci	unsigned char tmp, xpix;
132062306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	/* no range checks for xoffset and yoffset,   */
132362306a36Sopenharmony_ci	/* as fb_pan_display has already done this */
132462306a36Sopenharmony_ci	if (var->vmode & FB_VMODE_YWRAP)
132562306a36Sopenharmony_ci		return -EINVAL;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	xoffset = var->xoffset * info->var.bits_per_pixel / 8;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	base = var->yoffset * info->fix.line_length + xoffset;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (info->var.bits_per_pixel == 1) {
133262306a36Sopenharmony_ci		/* base is already correct */
133362306a36Sopenharmony_ci		xpix = (unsigned char) (var->xoffset % 8);
133462306a36Sopenharmony_ci	} else {
133562306a36Sopenharmony_ci		base /= 4;
133662306a36Sopenharmony_ci		xpix = (unsigned char) ((xoffset % 4) * 2);
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (!is_laguna(cinfo))
134062306a36Sopenharmony_ci		cirrusfb_WaitBLT(cinfo->regbase);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	/* lower 8 + 8 bits of screen start address */
134362306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff);
134462306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* 0xf2 is %11110010, exclude tmp bits */
134762306a36Sopenharmony_ci	tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2;
134862306a36Sopenharmony_ci	/* construct bits 16, 17 and 18 of screen start address */
134962306a36Sopenharmony_ci	if (base & 0x10000)
135062306a36Sopenharmony_ci		tmp |= 0x01;
135162306a36Sopenharmony_ci	if (base & 0x20000)
135262306a36Sopenharmony_ci		tmp |= 0x04;
135362306a36Sopenharmony_ci	if (base & 0x40000)
135462306a36Sopenharmony_ci		tmp |= 0x08;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, CL_CRT1B, tmp);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	/* construct bit 19 of screen start address */
135962306a36Sopenharmony_ci	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
136062306a36Sopenharmony_ci		tmp = vga_rcrt(cinfo->regbase, CL_CRT1D);
136162306a36Sopenharmony_ci		if (is_laguna(cinfo))
136262306a36Sopenharmony_ci			tmp = (tmp & ~0x18) | ((base >> 16) & 0x18);
136362306a36Sopenharmony_ci		else
136462306a36Sopenharmony_ci			tmp = (tmp & ~0x80) | ((base >> 12) & 0x80);
136562306a36Sopenharmony_ci		vga_wcrt(cinfo->regbase, CL_CRT1D, tmp);
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	/* write pixel panning value to AR33; this does not quite work in 8bpp
136962306a36Sopenharmony_ci	 *
137062306a36Sopenharmony_ci	 * ### Piccolo..? Will this work?
137162306a36Sopenharmony_ci	 */
137262306a36Sopenharmony_ci	if (info->var.bits_per_pixel == 1)
137362306a36Sopenharmony_ci		vga_wattr(cinfo->regbase, CL_AR33, xpix);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	return 0;
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic int cirrusfb_blank(int blank_mode, struct fb_info *info)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	/*
138162306a36Sopenharmony_ci	 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
138262306a36Sopenharmony_ci	 * then the caller blanks by setting the CLUT (Color Look Up Table)
138362306a36Sopenharmony_ci	 * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
138462306a36Sopenharmony_ci	 * failed due to e.g. a video mode which doesn't support it.
138562306a36Sopenharmony_ci	 * Implements VESA suspend and powerdown modes on hardware that
138662306a36Sopenharmony_ci	 * supports disabling hsync/vsync:
138762306a36Sopenharmony_ci	 *   blank_mode == 2: suspend vsync
138862306a36Sopenharmony_ci	 *   blank_mode == 3: suspend hsync
138962306a36Sopenharmony_ci	 *   blank_mode == 4: powerdown
139062306a36Sopenharmony_ci	 */
139162306a36Sopenharmony_ci	unsigned char val;
139262306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
139362306a36Sopenharmony_ci	int current_mode = cinfo->blank_mode;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING ||
139862306a36Sopenharmony_ci	    current_mode == blank_mode) {
139962306a36Sopenharmony_ci		dev_dbg(info->device, "EXIT, returning 0\n");
140062306a36Sopenharmony_ci		return 0;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	/* Undo current */
140462306a36Sopenharmony_ci	if (current_mode == FB_BLANK_NORMAL ||
140562306a36Sopenharmony_ci	    current_mode == FB_BLANK_UNBLANK)
140662306a36Sopenharmony_ci		/* clear "FullBandwidth" bit */
140762306a36Sopenharmony_ci		val = 0;
140862306a36Sopenharmony_ci	else
140962306a36Sopenharmony_ci		/* set "FullBandwidth" bit */
141062306a36Sopenharmony_ci		val = 0x20;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf;
141362306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	switch (blank_mode) {
141662306a36Sopenharmony_ci	case FB_BLANK_UNBLANK:
141762306a36Sopenharmony_ci	case FB_BLANK_NORMAL:
141862306a36Sopenharmony_ci		val = 0x00;
141962306a36Sopenharmony_ci		break;
142062306a36Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
142162306a36Sopenharmony_ci		val = 0x04;
142262306a36Sopenharmony_ci		break;
142362306a36Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
142462306a36Sopenharmony_ci		val = 0x02;
142562306a36Sopenharmony_ci		break;
142662306a36Sopenharmony_ci	case FB_BLANK_POWERDOWN:
142762306a36Sopenharmony_ci		val = 0x06;
142862306a36Sopenharmony_ci		break;
142962306a36Sopenharmony_ci	default:
143062306a36Sopenharmony_ci		dev_dbg(info->device, "EXIT, returning 1\n");
143162306a36Sopenharmony_ci		return 1;
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRE, val);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	cinfo->blank_mode = blank_mode;
143762306a36Sopenharmony_ci	dev_dbg(info->device, "EXIT, returning 0\n");
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	/* Let fbcon do a soft blank for us */
144062306a36Sopenharmony_ci	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci/**** END   Hardware specific Routines **************************************/
144462306a36Sopenharmony_ci/****************************************************************************/
144562306a36Sopenharmony_ci/**** BEGIN Internal Routines ***********************************************/
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic void init_vgachip(struct fb_info *info)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
145062306a36Sopenharmony_ci	const struct cirrusfb_board_info_rec *bi;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	assert(cinfo != NULL);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	bi = &cirrusfb_board_info[cinfo->btype];
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/* reset board globally */
145762306a36Sopenharmony_ci	switch (cinfo->btype) {
145862306a36Sopenharmony_ci	case BT_PICCOLO:
145962306a36Sopenharmony_ci		WSFR(cinfo, 0x01);
146062306a36Sopenharmony_ci		udelay(500);
146162306a36Sopenharmony_ci		WSFR(cinfo, 0x51);
146262306a36Sopenharmony_ci		udelay(500);
146362306a36Sopenharmony_ci		break;
146462306a36Sopenharmony_ci	case BT_PICASSO:
146562306a36Sopenharmony_ci		WSFR2(cinfo, 0xff);
146662306a36Sopenharmony_ci		udelay(500);
146762306a36Sopenharmony_ci		break;
146862306a36Sopenharmony_ci	case BT_SD64:
146962306a36Sopenharmony_ci	case BT_SPECTRUM:
147062306a36Sopenharmony_ci		WSFR(cinfo, 0x1f);
147162306a36Sopenharmony_ci		udelay(500);
147262306a36Sopenharmony_ci		WSFR(cinfo, 0x4f);
147362306a36Sopenharmony_ci		udelay(500);
147462306a36Sopenharmony_ci		break;
147562306a36Sopenharmony_ci	case BT_PICASSO4:
147662306a36Sopenharmony_ci		/* disable flickerfixer */
147762306a36Sopenharmony_ci		vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
147862306a36Sopenharmony_ci		mdelay(100);
147962306a36Sopenharmony_ci		/* mode */
148062306a36Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
148162306a36Sopenharmony_ci		fallthrough;
148262306a36Sopenharmony_ci	case BT_GD5480:
148362306a36Sopenharmony_ci		/* from Klaus' NetBSD driver: */
148462306a36Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
148562306a36Sopenharmony_ci		fallthrough;
148662306a36Sopenharmony_ci	case BT_ALPINE:
148762306a36Sopenharmony_ci		/* put blitter into 542x compat */
148862306a36Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
148962306a36Sopenharmony_ci		break;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	case BT_LAGUNA:
149262306a36Sopenharmony_ci	case BT_LAGUNAB:
149362306a36Sopenharmony_ci		/* Nothing to do to reset the board. */
149462306a36Sopenharmony_ci		break;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	default:
149762306a36Sopenharmony_ci		dev_err(info->device, "Warning: Unknown board type\n");
149862306a36Sopenharmony_ci		break;
149962306a36Sopenharmony_ci	}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	/* make sure RAM size set by this point */
150262306a36Sopenharmony_ci	assert(info->screen_size > 0);
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	/* the P4 is not fully initialized here; I rely on it having been */
150562306a36Sopenharmony_ci	/* inited under AmigaOS already, which seems to work just fine    */
150662306a36Sopenharmony_ci	/* (Klaus advised to do it this way)			      */
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if (cinfo->btype != BT_PICASSO4) {
150962306a36Sopenharmony_ci		WGen(cinfo, CL_VSSM, 0x10);	/* EGS: 0x16 */
151062306a36Sopenharmony_ci		WGen(cinfo, CL_POS102, 0x01);
151162306a36Sopenharmony_ci		WGen(cinfo, CL_VSSM, 0x08);	/* EGS: 0x0e */
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci		if (cinfo->btype != BT_SD64)
151462306a36Sopenharmony_ci			WGen(cinfo, CL_VSSM2, 0x01);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		/* reset sequencer logic */
151762306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		/* FullBandwidth (video off) and 8/9 dot clock */
152062306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci		/* "magic cookie" - doesn't make any sense to me.. */
152362306a36Sopenharmony_ci/*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
152462306a36Sopenharmony_ci		/* unlock all extension registers */
152562306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci		switch (cinfo->btype) {
152862306a36Sopenharmony_ci		case BT_GD5480:
152962306a36Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
153062306a36Sopenharmony_ci			break;
153162306a36Sopenharmony_ci		case BT_ALPINE:
153262306a36Sopenharmony_ci		case BT_LAGUNA:
153362306a36Sopenharmony_ci		case BT_LAGUNAB:
153462306a36Sopenharmony_ci			break;
153562306a36Sopenharmony_ci		case BT_SD64:
153662306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
153762306a36Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
153862306a36Sopenharmony_ci#endif
153962306a36Sopenharmony_ci			break;
154062306a36Sopenharmony_ci		default:
154162306a36Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
154262306a36Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
154362306a36Sopenharmony_ci			break;
154462306a36Sopenharmony_ci		}
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci	/* plane mask: nothing */
154762306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
154862306a36Sopenharmony_ci	/* character map select: doesn't even matter in gx mode */
154962306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
155062306a36Sopenharmony_ci	/* memory mode: chain4, ext. memory */
155162306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	/* controller-internal base address of video memory */
155462306a36Sopenharmony_ci	if (bi->init_sr07)
155562306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	/*  vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
155862306a36Sopenharmony_ci	/* EEPROM control: shouldn't be necessary to write to this at all.. */
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/* graphics cursor X position (incomplete; position gives rem. 3 bits */
156162306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
156262306a36Sopenharmony_ci	/* graphics cursor Y position (..."... ) */
156362306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
156462306a36Sopenharmony_ci	/* graphics cursor attributes */
156562306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
156662306a36Sopenharmony_ci	/* graphics cursor pattern address */
156762306a36Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	/* writing these on a P4 might give problems..  */
157062306a36Sopenharmony_ci	if (cinfo->btype != BT_PICASSO4) {
157162306a36Sopenharmony_ci		/* configuration readback and ext. color */
157262306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
157362306a36Sopenharmony_ci		/* signature generator */
157462306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	/* Screen A preset row scan: none */
157862306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
157962306a36Sopenharmony_ci	/* Text cursor start: disable text cursor */
158062306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
158162306a36Sopenharmony_ci	/* Text cursor end: - */
158262306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
158362306a36Sopenharmony_ci	/* text cursor location high: 0 */
158462306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
158562306a36Sopenharmony_ci	/* text cursor location low: 0 */
158662306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	/* Underline Row scanline: - */
158962306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
159062306a36Sopenharmony_ci	/* ### add 0x40 for text modes with > 30 MHz pixclock */
159162306a36Sopenharmony_ci	/* ext. display controls: ext.adr. wrap */
159262306a36Sopenharmony_ci	vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Set/Reset registers: - */
159562306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
159662306a36Sopenharmony_ci	/* Set/Reset enable: - */
159762306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
159862306a36Sopenharmony_ci	/* Color Compare: - */
159962306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
160062306a36Sopenharmony_ci	/* Data Rotate: - */
160162306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
160262306a36Sopenharmony_ci	/* Read Map Select: - */
160362306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
160462306a36Sopenharmony_ci	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
160562306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
160662306a36Sopenharmony_ci	/* Miscellaneous: memory map base address, graphics mode */
160762306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
160862306a36Sopenharmony_ci	/* Color Don't care: involve all planes */
160962306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
161062306a36Sopenharmony_ci	/* Bit Mask: no mask at all */
161162306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 ||
161462306a36Sopenharmony_ci	    is_laguna(cinfo))
161562306a36Sopenharmony_ci		/* (5434 can't have bit 3 set for bitblt) */
161662306a36Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
161762306a36Sopenharmony_ci	else
161862306a36Sopenharmony_ci	/* Graphics controller mode extensions: finer granularity,
161962306a36Sopenharmony_ci	 * 8byte data latches
162062306a36Sopenharmony_ci	 */
162162306a36Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GRB, 0x28);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRC, 0xff);	/* Color Key compare: - */
162462306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRD, 0x00);	/* Color Key compare mask: - */
162562306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRE, 0x00);	/* Miscellaneous control: - */
162662306a36Sopenharmony_ci	/* Background color byte 1: - */
162762306a36Sopenharmony_ci	/*  vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
162862306a36Sopenharmony_ci	/*  vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	/* Attribute Controller palette registers: "identity mapping" */
163162306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
163262306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
163362306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
163462306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
163562306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
163662306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
163762306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
163862306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
163962306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
164062306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
164162306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
164262306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
164362306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
164462306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
164562306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
164662306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	/* Attribute Controller mode: graphics mode */
164962306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
165062306a36Sopenharmony_ci	/* Overscan color reg.: reg. 0 */
165162306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
165262306a36Sopenharmony_ci	/* Color Plane enable: Enable all 4 planes */
165362306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
165462306a36Sopenharmony_ci	/* Color Select: - */
165562306a36Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	WGen(cinfo, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	/* BLT Start/status: Blitter reset */
166062306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
166162306a36Sopenharmony_ci	/* - " -	   : "end-of-reset" */
166262306a36Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	/* misc... */
166562306a36Sopenharmony_ci	WHDR(cinfo, 0);	/* Hidden DAC register: - */
166662306a36Sopenharmony_ci	return;
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic void switch_monitor(struct cirrusfb_info *cinfo, int on)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci#ifdef CONFIG_ZORRO /* only works on Zorro boards */
167262306a36Sopenharmony_ci	static int IsOn = 0;	/* XXX not ok for multiple boards */
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO4)
167562306a36Sopenharmony_ci		return;		/* nothing to switch */
167662306a36Sopenharmony_ci	if (cinfo->btype == BT_ALPINE)
167762306a36Sopenharmony_ci		return;		/* nothing to switch */
167862306a36Sopenharmony_ci	if (cinfo->btype == BT_GD5480)
167962306a36Sopenharmony_ci		return;		/* nothing to switch */
168062306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
168162306a36Sopenharmony_ci		if ((on && !IsOn) || (!on && IsOn))
168262306a36Sopenharmony_ci			WSFR(cinfo, 0xff);
168362306a36Sopenharmony_ci		return;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci	if (on) {
168662306a36Sopenharmony_ci		switch (cinfo->btype) {
168762306a36Sopenharmony_ci		case BT_SD64:
168862306a36Sopenharmony_ci			WSFR(cinfo, cinfo->SFR | 0x21);
168962306a36Sopenharmony_ci			break;
169062306a36Sopenharmony_ci		case BT_PICCOLO:
169162306a36Sopenharmony_ci			WSFR(cinfo, cinfo->SFR | 0x28);
169262306a36Sopenharmony_ci			break;
169362306a36Sopenharmony_ci		case BT_SPECTRUM:
169462306a36Sopenharmony_ci			WSFR(cinfo, 0x6f);
169562306a36Sopenharmony_ci			break;
169662306a36Sopenharmony_ci		default: /* do nothing */ break;
169762306a36Sopenharmony_ci		}
169862306a36Sopenharmony_ci	} else {
169962306a36Sopenharmony_ci		switch (cinfo->btype) {
170062306a36Sopenharmony_ci		case BT_SD64:
170162306a36Sopenharmony_ci			WSFR(cinfo, cinfo->SFR & 0xde);
170262306a36Sopenharmony_ci			break;
170362306a36Sopenharmony_ci		case BT_PICCOLO:
170462306a36Sopenharmony_ci			WSFR(cinfo, cinfo->SFR & 0xd7);
170562306a36Sopenharmony_ci			break;
170662306a36Sopenharmony_ci		case BT_SPECTRUM:
170762306a36Sopenharmony_ci			WSFR(cinfo, 0x4f);
170862306a36Sopenharmony_ci			break;
170962306a36Sopenharmony_ci		default: /* do nothing */
171062306a36Sopenharmony_ci			break;
171162306a36Sopenharmony_ci		}
171262306a36Sopenharmony_ci	}
171362306a36Sopenharmony_ci#endif /* CONFIG_ZORRO */
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/******************************************/
171762306a36Sopenharmony_ci/* Linux 2.6-style  accelerated functions */
171862306a36Sopenharmony_ci/******************************************/
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic int cirrusfb_sync(struct fb_info *info)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	if (!is_laguna(cinfo)) {
172562306a36Sopenharmony_ci		while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03)
172662306a36Sopenharmony_ci			cpu_relax();
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci	return 0;
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_cistatic void cirrusfb_fillrect(struct fb_info *info,
173262306a36Sopenharmony_ci			      const struct fb_fillrect *region)
173362306a36Sopenharmony_ci{
173462306a36Sopenharmony_ci	struct fb_fillrect modded;
173562306a36Sopenharmony_ci	int vxres, vyres;
173662306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
173762306a36Sopenharmony_ci	int m = info->var.bits_per_pixel;
173862306a36Sopenharmony_ci	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
173962306a36Sopenharmony_ci		cinfo->pseudo_palette[region->color] : region->color;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
174262306a36Sopenharmony_ci		return;
174362306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED) {
174462306a36Sopenharmony_ci		cfb_fillrect(info, region);
174562306a36Sopenharmony_ci		return;
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	vxres = info->var.xres_virtual;
174962306a36Sopenharmony_ci	vyres = info->var.yres_virtual;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	memcpy(&modded, region, sizeof(struct fb_fillrect));
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	if (!modded.width || !modded.height ||
175462306a36Sopenharmony_ci	   modded.dx >= vxres || modded.dy >= vyres)
175562306a36Sopenharmony_ci		return;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	if (modded.dx + modded.width  > vxres)
175862306a36Sopenharmony_ci		modded.width  = vxres - modded.dx;
175962306a36Sopenharmony_ci	if (modded.dy + modded.height > vyres)
176062306a36Sopenharmony_ci		modded.height = vyres - modded.dy;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	cirrusfb_RectFill(cinfo->regbase,
176362306a36Sopenharmony_ci			  info->var.bits_per_pixel,
176462306a36Sopenharmony_ci			  (region->dx * m) / 8, region->dy,
176562306a36Sopenharmony_ci			  (region->width * m) / 8, region->height,
176662306a36Sopenharmony_ci			  color, color,
176762306a36Sopenharmony_ci			  info->fix.line_length, 0x40);
176862306a36Sopenharmony_ci}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_cistatic void cirrusfb_copyarea(struct fb_info *info,
177162306a36Sopenharmony_ci			      const struct fb_copyarea *area)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct fb_copyarea modded;
177462306a36Sopenharmony_ci	u32 vxres, vyres;
177562306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
177662306a36Sopenharmony_ci	int m = info->var.bits_per_pixel;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
177962306a36Sopenharmony_ci		return;
178062306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED) {
178162306a36Sopenharmony_ci		cfb_copyarea(info, area);
178262306a36Sopenharmony_ci		return;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	vxres = info->var.xres_virtual;
178662306a36Sopenharmony_ci	vyres = info->var.yres_virtual;
178762306a36Sopenharmony_ci	memcpy(&modded, area, sizeof(struct fb_copyarea));
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	if (!modded.width || !modded.height ||
179062306a36Sopenharmony_ci	   modded.sx >= vxres || modded.sy >= vyres ||
179162306a36Sopenharmony_ci	   modded.dx >= vxres || modded.dy >= vyres)
179262306a36Sopenharmony_ci		return;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (modded.sx + modded.width > vxres)
179562306a36Sopenharmony_ci		modded.width = vxres - modded.sx;
179662306a36Sopenharmony_ci	if (modded.dx + modded.width > vxres)
179762306a36Sopenharmony_ci		modded.width = vxres - modded.dx;
179862306a36Sopenharmony_ci	if (modded.sy + modded.height > vyres)
179962306a36Sopenharmony_ci		modded.height = vyres - modded.sy;
180062306a36Sopenharmony_ci	if (modded.dy + modded.height > vyres)
180162306a36Sopenharmony_ci		modded.height = vyres - modded.dy;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
180462306a36Sopenharmony_ci			(area->sx * m) / 8, area->sy,
180562306a36Sopenharmony_ci			(area->dx * m) / 8, area->dy,
180662306a36Sopenharmony_ci			(area->width * m) / 8, area->height,
180762306a36Sopenharmony_ci			info->fix.line_length);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_cistatic void cirrusfb_imageblit(struct fb_info *info,
181262306a36Sopenharmony_ci			       const struct fb_image *image)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
181562306a36Sopenharmony_ci	unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
181862306a36Sopenharmony_ci		return;
181962306a36Sopenharmony_ci	/* Alpine/SD64 does not work at 24bpp ??? */
182062306a36Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
182162306a36Sopenharmony_ci		cfb_imageblit(info, image);
182262306a36Sopenharmony_ci	else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) &&
182362306a36Sopenharmony_ci		  op == 0xc)
182462306a36Sopenharmony_ci		cfb_imageblit(info, image);
182562306a36Sopenharmony_ci	else {
182662306a36Sopenharmony_ci		unsigned size = ((image->width + 7) >> 3) * image->height;
182762306a36Sopenharmony_ci		int m = info->var.bits_per_pixel;
182862306a36Sopenharmony_ci		u32 fg, bg;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci		if (info->var.bits_per_pixel == 8) {
183162306a36Sopenharmony_ci			fg = image->fg_color;
183262306a36Sopenharmony_ci			bg = image->bg_color;
183362306a36Sopenharmony_ci		} else {
183462306a36Sopenharmony_ci			fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
183562306a36Sopenharmony_ci			bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
183662306a36Sopenharmony_ci		}
183762306a36Sopenharmony_ci		if (info->var.bits_per_pixel == 24) {
183862306a36Sopenharmony_ci			/* clear background first */
183962306a36Sopenharmony_ci			cirrusfb_RectFill(cinfo->regbase,
184062306a36Sopenharmony_ci					  info->var.bits_per_pixel,
184162306a36Sopenharmony_ci					  (image->dx * m) / 8, image->dy,
184262306a36Sopenharmony_ci					  (image->width * m) / 8,
184362306a36Sopenharmony_ci					  image->height,
184462306a36Sopenharmony_ci					  bg, bg,
184562306a36Sopenharmony_ci					  info->fix.line_length, 0x40);
184662306a36Sopenharmony_ci		}
184762306a36Sopenharmony_ci		cirrusfb_RectFill(cinfo->regbase,
184862306a36Sopenharmony_ci				  info->var.bits_per_pixel,
184962306a36Sopenharmony_ci				  (image->dx * m) / 8, image->dy,
185062306a36Sopenharmony_ci				  (image->width * m) / 8, image->height,
185162306a36Sopenharmony_ci				  fg, bg,
185262306a36Sopenharmony_ci				  info->fix.line_length, op);
185362306a36Sopenharmony_ci		memcpy(info->screen_base, image->data, size);
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci}
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci#ifdef CONFIG_PCI
185862306a36Sopenharmony_cistatic int release_io_ports;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
186162306a36Sopenharmony_ci * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
186262306a36Sopenharmony_ci * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
186362306a36Sopenharmony_ci * seem to have. */
186462306a36Sopenharmony_cistatic unsigned int cirrusfb_get_memsize(struct fb_info *info,
186562306a36Sopenharmony_ci					 u8 __iomem *regbase)
186662306a36Sopenharmony_ci{
186762306a36Sopenharmony_ci	unsigned long mem;
186862306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	if (is_laguna(cinfo)) {
187162306a36Sopenharmony_ci		unsigned char SR14 = vga_rseq(regbase, CL_SEQR14);
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci		mem = ((SR14 & 7) + 1) << 20;
187462306a36Sopenharmony_ci	} else {
187562306a36Sopenharmony_ci		unsigned char SRF = vga_rseq(regbase, CL_SEQRF);
187662306a36Sopenharmony_ci		switch ((SRF & 0x18)) {
187762306a36Sopenharmony_ci		case 0x08:
187862306a36Sopenharmony_ci			mem = 512 * 1024;
187962306a36Sopenharmony_ci			break;
188062306a36Sopenharmony_ci		case 0x10:
188162306a36Sopenharmony_ci			mem = 1024 * 1024;
188262306a36Sopenharmony_ci			break;
188362306a36Sopenharmony_ci		/* 64-bit DRAM data bus width; assume 2MB.
188462306a36Sopenharmony_ci		 * Also indicates 2MB memory on the 5430.
188562306a36Sopenharmony_ci		 */
188662306a36Sopenharmony_ci		case 0x18:
188762306a36Sopenharmony_ci			mem = 2048 * 1024;
188862306a36Sopenharmony_ci			break;
188962306a36Sopenharmony_ci		default:
189062306a36Sopenharmony_ci			dev_warn(info->device, "Unknown memory size!\n");
189162306a36Sopenharmony_ci			mem = 1024 * 1024;
189262306a36Sopenharmony_ci		}
189362306a36Sopenharmony_ci		/* If DRAM bank switching is enabled, there must be
189462306a36Sopenharmony_ci		 * twice as much memory installed. (4MB on the 5434)
189562306a36Sopenharmony_ci		 */
189662306a36Sopenharmony_ci		if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0)
189762306a36Sopenharmony_ci			mem *= 2;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
190162306a36Sopenharmony_ci	return mem;
190262306a36Sopenharmony_ci}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_cistatic void get_pci_addrs(const struct pci_dev *pdev,
190562306a36Sopenharmony_ci			  unsigned long *display, unsigned long *registers)
190662306a36Sopenharmony_ci{
190762306a36Sopenharmony_ci	assert(pdev != NULL);
190862306a36Sopenharmony_ci	assert(display != NULL);
190962306a36Sopenharmony_ci	assert(registers != NULL);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	*display = 0;
191262306a36Sopenharmony_ci	*registers = 0;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	/* This is a best-guess for now */
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
191762306a36Sopenharmony_ci		*display = pci_resource_start(pdev, 1);
191862306a36Sopenharmony_ci		*registers = pci_resource_start(pdev, 0);
191962306a36Sopenharmony_ci	} else {
192062306a36Sopenharmony_ci		*display = pci_resource_start(pdev, 0);
192162306a36Sopenharmony_ci		*registers = pci_resource_start(pdev, 1);
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	assert(*display != 0);
192562306a36Sopenharmony_ci}
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_cistatic void cirrusfb_pci_unmap(struct fb_info *info)
192862306a36Sopenharmony_ci{
192962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(info->device);
193062306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	if (cinfo->laguna_mmio == NULL)
193362306a36Sopenharmony_ci		iounmap(cinfo->laguna_mmio);
193462306a36Sopenharmony_ci	iounmap(info->screen_base);
193562306a36Sopenharmony_ci#if 0 /* if system didn't claim this region, we would... */
193662306a36Sopenharmony_ci	release_mem_region(0xA0000, 65535);
193762306a36Sopenharmony_ci#endif
193862306a36Sopenharmony_ci	if (release_io_ports)
193962306a36Sopenharmony_ci		release_region(0x3C0, 32);
194062306a36Sopenharmony_ci	pci_release_regions(pdev);
194162306a36Sopenharmony_ci}
194262306a36Sopenharmony_ci#endif /* CONFIG_PCI */
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
194562306a36Sopenharmony_cistatic void cirrusfb_zorro_unmap(struct fb_info *info)
194662306a36Sopenharmony_ci{
194762306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
194862306a36Sopenharmony_ci	struct zorro_dev *zdev = to_zorro_dev(info->device);
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (info->fix.smem_start > 16 * MB_)
195162306a36Sopenharmony_ci		iounmap(info->screen_base);
195262306a36Sopenharmony_ci	if (info->fix.mmio_start > 16 * MB_)
195362306a36Sopenharmony_ci		iounmap(cinfo->regbase);
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	zorro_release_device(zdev);
195662306a36Sopenharmony_ci}
195762306a36Sopenharmony_ci#endif /* CONFIG_ZORRO */
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci/* function table of the above functions */
196062306a36Sopenharmony_cistatic const struct fb_ops cirrusfb_ops = {
196162306a36Sopenharmony_ci	.owner		= THIS_MODULE,
196262306a36Sopenharmony_ci	.fb_open	= cirrusfb_open,
196362306a36Sopenharmony_ci	.fb_release	= cirrusfb_release,
196462306a36Sopenharmony_ci	.fb_setcolreg	= cirrusfb_setcolreg,
196562306a36Sopenharmony_ci	.fb_check_var	= cirrusfb_check_var,
196662306a36Sopenharmony_ci	.fb_set_par	= cirrusfb_set_par,
196762306a36Sopenharmony_ci	.fb_pan_display = cirrusfb_pan_display,
196862306a36Sopenharmony_ci	.fb_blank	= cirrusfb_blank,
196962306a36Sopenharmony_ci	.fb_fillrect	= cirrusfb_fillrect,
197062306a36Sopenharmony_ci	.fb_copyarea	= cirrusfb_copyarea,
197162306a36Sopenharmony_ci	.fb_sync	= cirrusfb_sync,
197262306a36Sopenharmony_ci	.fb_imageblit	= cirrusfb_imageblit,
197362306a36Sopenharmony_ci};
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_cistatic int cirrusfb_set_fbinfo(struct fb_info *info)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
197862306a36Sopenharmony_ci	struct fb_var_screeninfo *var = &info->var;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	info->pseudo_palette = cinfo->pseudo_palette;
198162306a36Sopenharmony_ci	info->flags = FBINFO_HWACCEL_XPAN
198262306a36Sopenharmony_ci		    | FBINFO_HWACCEL_YPAN
198362306a36Sopenharmony_ci		    | FBINFO_HWACCEL_FILLRECT
198462306a36Sopenharmony_ci		    | FBINFO_HWACCEL_IMAGEBLIT
198562306a36Sopenharmony_ci		    | FBINFO_HWACCEL_COPYAREA;
198662306a36Sopenharmony_ci	if (noaccel || is_laguna(cinfo)) {
198762306a36Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_DISABLED;
198862306a36Sopenharmony_ci		info->fix.accel = FB_ACCEL_NONE;
198962306a36Sopenharmony_ci	} else
199062306a36Sopenharmony_ci		info->fix.accel = FB_ACCEL_CIRRUS_ALPINE;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	info->fbops = &cirrusfb_ops;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	if (cinfo->btype == BT_GD5480) {
199562306a36Sopenharmony_ci		if (var->bits_per_pixel == 16)
199662306a36Sopenharmony_ci			info->screen_base += 1 * MB_;
199762306a36Sopenharmony_ci		if (var->bits_per_pixel == 32)
199862306a36Sopenharmony_ci			info->screen_base += 2 * MB_;
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	/* Fill fix common fields */
200262306a36Sopenharmony_ci	strscpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
200362306a36Sopenharmony_ci		sizeof(info->fix.id));
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	/* monochrome: only 1 memory plane */
200662306a36Sopenharmony_ci	/* 8 bit and above: Use whole memory area */
200762306a36Sopenharmony_ci	info->fix.smem_len   = info->screen_size;
200862306a36Sopenharmony_ci	if (var->bits_per_pixel == 1)
200962306a36Sopenharmony_ci		info->fix.smem_len /= 4;
201062306a36Sopenharmony_ci	info->fix.type_aux   = 0;
201162306a36Sopenharmony_ci	info->fix.xpanstep   = 1;
201262306a36Sopenharmony_ci	info->fix.ypanstep   = 1;
201362306a36Sopenharmony_ci	info->fix.ywrapstep  = 0;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/* FIXME: map region at 0xB8000 if available, fill in here */
201662306a36Sopenharmony_ci	info->fix.mmio_len   = 0;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	fb_alloc_cmap(&info->cmap, 256, 0);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	return 0;
202162306a36Sopenharmony_ci}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_cistatic int cirrusfb_register(struct fb_info *info)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
202662306a36Sopenharmony_ci	int err;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	/* sanity checks */
202962306a36Sopenharmony_ci	assert(cinfo->btype != BT_NONE);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	/* set all the vital stuff */
203262306a36Sopenharmony_ci	cirrusfb_set_fbinfo(info);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base);
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
203762306a36Sopenharmony_ci	if (!err) {
203862306a36Sopenharmony_ci		dev_dbg(info->device, "wrong initial video mode\n");
203962306a36Sopenharmony_ci		err = -EINVAL;
204062306a36Sopenharmony_ci		goto err_dealloc_cmap;
204162306a36Sopenharmony_ci	}
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	info->var.activate = FB_ACTIVATE_NOW;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	err = cirrusfb_check_var(&info->var, info);
204662306a36Sopenharmony_ci	if (err < 0) {
204762306a36Sopenharmony_ci		/* should never happen */
204862306a36Sopenharmony_ci		dev_dbg(info->device,
204962306a36Sopenharmony_ci			"choking on default var... umm, no good.\n");
205062306a36Sopenharmony_ci		goto err_dealloc_cmap;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	err = register_framebuffer(info);
205462306a36Sopenharmony_ci	if (err < 0) {
205562306a36Sopenharmony_ci		dev_err(info->device,
205662306a36Sopenharmony_ci			"could not register fb device; err = %d!\n", err);
205762306a36Sopenharmony_ci		goto err_dealloc_cmap;
205862306a36Sopenharmony_ci	}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	return 0;
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_cierr_dealloc_cmap:
206362306a36Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
206462306a36Sopenharmony_ci	return err;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_cistatic void cirrusfb_cleanup(struct fb_info *info)
206862306a36Sopenharmony_ci{
206962306a36Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	switch_monitor(cinfo, 0);
207262306a36Sopenharmony_ci	unregister_framebuffer(info);
207362306a36Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
207462306a36Sopenharmony_ci	dev_dbg(info->device, "Framebuffer unregistered\n");
207562306a36Sopenharmony_ci	cinfo->unmap(info);
207662306a36Sopenharmony_ci	framebuffer_release(info);
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci#ifdef CONFIG_PCI
208062306a36Sopenharmony_cistatic int cirrusfb_pci_register(struct pci_dev *pdev,
208162306a36Sopenharmony_ci				 const struct pci_device_id *ent)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	struct cirrusfb_info *cinfo;
208462306a36Sopenharmony_ci	struct fb_info *info;
208562306a36Sopenharmony_ci	unsigned long board_addr, board_size;
208662306a36Sopenharmony_ci	int ret;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	ret = aperture_remove_conflicting_pci_devices(pdev, "cirrusfb");
208962306a36Sopenharmony_ci	if (ret)
209062306a36Sopenharmony_ci		return ret;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
209362306a36Sopenharmony_ci	if (ret < 0) {
209462306a36Sopenharmony_ci		printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
209562306a36Sopenharmony_ci		goto err_out;
209662306a36Sopenharmony_ci	}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
209962306a36Sopenharmony_ci	if (!info) {
210062306a36Sopenharmony_ci		ret = -ENOMEM;
210162306a36Sopenharmony_ci		goto err_out;
210262306a36Sopenharmony_ci	}
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	cinfo = info->par;
210562306a36Sopenharmony_ci	cinfo->btype = (enum cirrus_board) ent->driver_data;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	dev_dbg(info->device,
210862306a36Sopenharmony_ci		" Found PCI device, base address 0 is 0x%Lx, btype set to %d\n",
210962306a36Sopenharmony_ci		(unsigned long long)pdev->resource[0].start,  cinfo->btype);
211062306a36Sopenharmony_ci	dev_dbg(info->device, " base address 1 is 0x%Lx\n",
211162306a36Sopenharmony_ci		(unsigned long long)pdev->resource[1].start);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	dev_dbg(info->device,
211462306a36Sopenharmony_ci		"Attempt to get PCI info for Cirrus Graphics Card\n");
211562306a36Sopenharmony_ci	get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
211662306a36Sopenharmony_ci	/* FIXME: this forces VGA.  alternatives? */
211762306a36Sopenharmony_ci	cinfo->regbase = NULL;
211862306a36Sopenharmony_ci	cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n",
212162306a36Sopenharmony_ci		board_addr, info->fix.mmio_start);
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	board_size = (cinfo->btype == BT_GD5480) ?
212462306a36Sopenharmony_ci		32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	ret = pci_request_regions(pdev, "cirrusfb");
212762306a36Sopenharmony_ci	if (ret < 0) {
212862306a36Sopenharmony_ci		dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
212962306a36Sopenharmony_ci			board_addr);
213062306a36Sopenharmony_ci		goto err_release_fb;
213162306a36Sopenharmony_ci	}
213262306a36Sopenharmony_ci#if 0 /* if the system didn't claim this region, we would... */
213362306a36Sopenharmony_ci	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
213462306a36Sopenharmony_ci		dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
213562306a36Sopenharmony_ci			0xA0000L);
213662306a36Sopenharmony_ci		ret = -EBUSY;
213762306a36Sopenharmony_ci		goto err_release_regions;
213862306a36Sopenharmony_ci	}
213962306a36Sopenharmony_ci#endif
214062306a36Sopenharmony_ci	if (request_region(0x3C0, 32, "cirrusfb"))
214162306a36Sopenharmony_ci		release_io_ports = 1;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	info->screen_base = ioremap(board_addr, board_size);
214462306a36Sopenharmony_ci	if (!info->screen_base) {
214562306a36Sopenharmony_ci		ret = -EIO;
214662306a36Sopenharmony_ci		goto err_release_legacy;
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	info->fix.smem_start = board_addr;
215062306a36Sopenharmony_ci	info->screen_size = board_size;
215162306a36Sopenharmony_ci	cinfo->unmap = cirrusfb_pci_unmap;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	dev_info(info->device,
215462306a36Sopenharmony_ci		 "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n",
215562306a36Sopenharmony_ci		 info->screen_size >> 10, board_addr);
215662306a36Sopenharmony_ci	pci_set_drvdata(pdev, info);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	ret = cirrusfb_register(info);
215962306a36Sopenharmony_ci	if (!ret)
216062306a36Sopenharmony_ci		return 0;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	iounmap(info->screen_base);
216362306a36Sopenharmony_cierr_release_legacy:
216462306a36Sopenharmony_ci	if (release_io_ports)
216562306a36Sopenharmony_ci		release_region(0x3C0, 32);
216662306a36Sopenharmony_ci#if 0
216762306a36Sopenharmony_ci	release_mem_region(0xA0000, 65535);
216862306a36Sopenharmony_cierr_release_regions:
216962306a36Sopenharmony_ci#endif
217062306a36Sopenharmony_ci	pci_release_regions(pdev);
217162306a36Sopenharmony_cierr_release_fb:
217262306a36Sopenharmony_ci	if (cinfo->laguna_mmio != NULL)
217362306a36Sopenharmony_ci		iounmap(cinfo->laguna_mmio);
217462306a36Sopenharmony_ci	framebuffer_release(info);
217562306a36Sopenharmony_cierr_out:
217662306a36Sopenharmony_ci	return ret;
217762306a36Sopenharmony_ci}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_cistatic void cirrusfb_pci_unregister(struct pci_dev *pdev)
218062306a36Sopenharmony_ci{
218162306a36Sopenharmony_ci	struct fb_info *info = pci_get_drvdata(pdev);
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	cirrusfb_cleanup(info);
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_cistatic struct pci_driver cirrusfb_pci_driver = {
218762306a36Sopenharmony_ci	.name		= "cirrusfb",
218862306a36Sopenharmony_ci	.id_table	= cirrusfb_pci_table,
218962306a36Sopenharmony_ci	.probe		= cirrusfb_pci_register,
219062306a36Sopenharmony_ci	.remove		= cirrusfb_pci_unregister,
219162306a36Sopenharmony_ci};
219262306a36Sopenharmony_ci#endif /* CONFIG_PCI */
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
219562306a36Sopenharmony_cistatic int cirrusfb_zorro_register(struct zorro_dev *z,
219662306a36Sopenharmony_ci				   const struct zorro_device_id *ent)
219762306a36Sopenharmony_ci{
219862306a36Sopenharmony_ci	struct fb_info *info;
219962306a36Sopenharmony_ci	int error;
220062306a36Sopenharmony_ci	const struct zorrocl *zcl;
220162306a36Sopenharmony_ci	enum cirrus_board btype;
220262306a36Sopenharmony_ci	unsigned long regbase, ramsize, rambase;
220362306a36Sopenharmony_ci	struct cirrusfb_info *cinfo;
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
220662306a36Sopenharmony_ci	if (!info)
220762306a36Sopenharmony_ci		return -ENOMEM;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	zcl = (const struct zorrocl *)ent->driver_data;
221062306a36Sopenharmony_ci	btype = zcl->type;
221162306a36Sopenharmony_ci	regbase = zorro_resource_start(z) + zcl->regoffset;
221262306a36Sopenharmony_ci	ramsize = zcl->ramsize;
221362306a36Sopenharmony_ci	if (ramsize) {
221462306a36Sopenharmony_ci		rambase = zorro_resource_start(z) + zcl->ramoffset;
221562306a36Sopenharmony_ci		if (zorro_resource_len(z) == 64 * MB_) {
221662306a36Sopenharmony_ci			/* Quirk for 64 MiB Picasso IV */
221762306a36Sopenharmony_ci			rambase += zcl->ramoffset;
221862306a36Sopenharmony_ci		}
221962306a36Sopenharmony_ci	} else {
222062306a36Sopenharmony_ci		struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
222162306a36Sopenharmony_ci		if (!ram || !zorro_resource_len(ram)) {
222262306a36Sopenharmony_ci			dev_err(info->device, "No video RAM found\n");
222362306a36Sopenharmony_ci			error = -ENODEV;
222462306a36Sopenharmony_ci			goto err_release_fb;
222562306a36Sopenharmony_ci		}
222662306a36Sopenharmony_ci		rambase = zorro_resource_start(ram);
222762306a36Sopenharmony_ci		ramsize = zorro_resource_len(ram);
222862306a36Sopenharmony_ci		if (zcl->ramid2 &&
222962306a36Sopenharmony_ci		    (ram = zorro_find_device(zcl->ramid2, NULL))) {
223062306a36Sopenharmony_ci			if (zorro_resource_start(ram) != rambase + ramsize) {
223162306a36Sopenharmony_ci				dev_warn(info->device,
223262306a36Sopenharmony_ci					 "Skipping non-contiguous RAM at %pR\n",
223362306a36Sopenharmony_ci					 &ram->resource);
223462306a36Sopenharmony_ci			} else {
223562306a36Sopenharmony_ci				ramsize += zorro_resource_len(ram);
223662306a36Sopenharmony_ci			}
223762306a36Sopenharmony_ci		}
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	dev_info(info->device,
224162306a36Sopenharmony_ci		 "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n",
224262306a36Sopenharmony_ci		 cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
224362306a36Sopenharmony_ci		 rambase);
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	if (!zorro_request_device(z, "cirrusfb")) {
224662306a36Sopenharmony_ci		dev_err(info->device, "Cannot reserve %pR\n", &z->resource);
224762306a36Sopenharmony_ci		error = -EBUSY;
224862306a36Sopenharmony_ci		goto err_release_fb;
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	cinfo = info->par;
225262306a36Sopenharmony_ci	cinfo->btype = btype;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	info->fix.mmio_start = regbase;
225562306a36Sopenharmony_ci	cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
225662306a36Sopenharmony_ci					    : ZTWO_VADDR(regbase);
225762306a36Sopenharmony_ci	if (!cinfo->regbase) {
225862306a36Sopenharmony_ci		dev_err(info->device, "Cannot map registers\n");
225962306a36Sopenharmony_ci		error = -EIO;
226062306a36Sopenharmony_ci		goto err_release_dev;
226162306a36Sopenharmony_ci	}
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	info->fix.smem_start = rambase;
226462306a36Sopenharmony_ci	info->screen_size = ramsize;
226562306a36Sopenharmony_ci	info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
226662306a36Sopenharmony_ci					       : ZTWO_VADDR(rambase);
226762306a36Sopenharmony_ci	if (!info->screen_base) {
226862306a36Sopenharmony_ci		dev_err(info->device, "Cannot map video RAM\n");
226962306a36Sopenharmony_ci		error = -EIO;
227062306a36Sopenharmony_ci		goto err_unmap_reg;
227162306a36Sopenharmony_ci	}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci	cinfo->unmap = cirrusfb_zorro_unmap;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	dev_info(info->device,
227662306a36Sopenharmony_ci		 "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n",
227762306a36Sopenharmony_ci		 ramsize / MB_, rambase);
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	/* MCLK select etc. */
228062306a36Sopenharmony_ci	if (cirrusfb_board_info[btype].init_sr1f)
228162306a36Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR1F,
228262306a36Sopenharmony_ci			 cirrusfb_board_info[btype].sr1f);
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	error = cirrusfb_register(info);
228562306a36Sopenharmony_ci	if (error) {
228662306a36Sopenharmony_ci		dev_err(info->device, "Failed to register device, error %d\n",
228762306a36Sopenharmony_ci			error);
228862306a36Sopenharmony_ci		goto err_unmap_ram;
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	zorro_set_drvdata(z, info);
229262306a36Sopenharmony_ci	return 0;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_cierr_unmap_ram:
229562306a36Sopenharmony_ci	if (rambase > 16 * MB_)
229662306a36Sopenharmony_ci		iounmap(info->screen_base);
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_cierr_unmap_reg:
229962306a36Sopenharmony_ci	if (regbase > 16 * MB_)
230062306a36Sopenharmony_ci		iounmap(cinfo->regbase);
230162306a36Sopenharmony_cierr_release_dev:
230262306a36Sopenharmony_ci	zorro_release_device(z);
230362306a36Sopenharmony_cierr_release_fb:
230462306a36Sopenharmony_ci	framebuffer_release(info);
230562306a36Sopenharmony_ci	return error;
230662306a36Sopenharmony_ci}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_cistatic void cirrusfb_zorro_unregister(struct zorro_dev *z)
230962306a36Sopenharmony_ci{
231062306a36Sopenharmony_ci	struct fb_info *info = zorro_get_drvdata(z);
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	cirrusfb_cleanup(info);
231362306a36Sopenharmony_ci	zorro_set_drvdata(z, NULL);
231462306a36Sopenharmony_ci}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_cistatic struct zorro_driver cirrusfb_zorro_driver = {
231762306a36Sopenharmony_ci	.name		= "cirrusfb",
231862306a36Sopenharmony_ci	.id_table	= cirrusfb_zorro_table,
231962306a36Sopenharmony_ci	.probe		= cirrusfb_zorro_register,
232062306a36Sopenharmony_ci	.remove		= cirrusfb_zorro_unregister,
232162306a36Sopenharmony_ci};
232262306a36Sopenharmony_ci#endif /* CONFIG_ZORRO */
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci#ifndef MODULE
232562306a36Sopenharmony_cistatic int __init cirrusfb_setup(char *options)
232662306a36Sopenharmony_ci{
232762306a36Sopenharmony_ci	char *this_opt;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	if (!options || !*options)
233062306a36Sopenharmony_ci		return 0;
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
233362306a36Sopenharmony_ci		if (!*this_opt)
233462306a36Sopenharmony_ci			continue;
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci		if (!strcmp(this_opt, "noaccel"))
233762306a36Sopenharmony_ci			noaccel = 1;
233862306a36Sopenharmony_ci		else if (!strncmp(this_opt, "mode:", 5))
233962306a36Sopenharmony_ci			mode_option = this_opt + 5;
234062306a36Sopenharmony_ci		else
234162306a36Sopenharmony_ci			mode_option = this_opt;
234262306a36Sopenharmony_ci	}
234362306a36Sopenharmony_ci	return 0;
234462306a36Sopenharmony_ci}
234562306a36Sopenharmony_ci#endif
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci    /*
234862306a36Sopenharmony_ci     *  Modularization
234962306a36Sopenharmony_ci     */
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ciMODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
235262306a36Sopenharmony_ciMODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
235362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_cistatic int __init cirrusfb_init(void)
235662306a36Sopenharmony_ci{
235762306a36Sopenharmony_ci	int error = 0;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci#ifndef MODULE
236062306a36Sopenharmony_ci	char *option = NULL;
236162306a36Sopenharmony_ci#endif
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (fb_modesetting_disabled("cirrusfb"))
236462306a36Sopenharmony_ci		return -ENODEV;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci#ifndef MODULE
236762306a36Sopenharmony_ci	if (fb_get_options("cirrusfb", &option))
236862306a36Sopenharmony_ci		return -ENODEV;
236962306a36Sopenharmony_ci	cirrusfb_setup(option);
237062306a36Sopenharmony_ci#endif
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
237362306a36Sopenharmony_ci	error |= zorro_register_driver(&cirrusfb_zorro_driver);
237462306a36Sopenharmony_ci#endif
237562306a36Sopenharmony_ci#ifdef CONFIG_PCI
237662306a36Sopenharmony_ci	error |= pci_register_driver(&cirrusfb_pci_driver);
237762306a36Sopenharmony_ci#endif
237862306a36Sopenharmony_ci	return error;
237962306a36Sopenharmony_ci}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_cistatic void __exit cirrusfb_exit(void)
238262306a36Sopenharmony_ci{
238362306a36Sopenharmony_ci#ifdef CONFIG_PCI
238462306a36Sopenharmony_ci	pci_unregister_driver(&cirrusfb_pci_driver);
238562306a36Sopenharmony_ci#endif
238662306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
238762306a36Sopenharmony_ci	zorro_unregister_driver(&cirrusfb_zorro_driver);
238862306a36Sopenharmony_ci#endif
238962306a36Sopenharmony_ci}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_cimodule_init(cirrusfb_init);
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_cimodule_param(mode_option, charp, 0);
239462306a36Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
239562306a36Sopenharmony_cimodule_param(noaccel, bool, 0);
239662306a36Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Disable acceleration");
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci#ifdef MODULE
239962306a36Sopenharmony_cimodule_exit(cirrusfb_exit);
240062306a36Sopenharmony_ci#endif
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci/**********************************************************************/
240362306a36Sopenharmony_ci/* about the following functions - I have used the same names for the */
240462306a36Sopenharmony_ci/* functions as Markus Wild did in his Retina driver for NetBSD as    */
240562306a36Sopenharmony_ci/* they just made sense for this purpose. Apart from that, I wrote    */
240662306a36Sopenharmony_ci/* these functions myself.					    */
240762306a36Sopenharmony_ci/**********************************************************************/
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci/*** WGen() - write into one of the external/general registers ***/
241062306a36Sopenharmony_cistatic void WGen(const struct cirrusfb_info *cinfo,
241162306a36Sopenharmony_ci		  int regnum, unsigned char val)
241262306a36Sopenharmony_ci{
241362306a36Sopenharmony_ci	unsigned long regofs = 0;
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
241662306a36Sopenharmony_ci		/* Picasso II specific hack */
241762306a36Sopenharmony_ci/*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
241862306a36Sopenharmony_ci		  regnum == CL_VSSM2) */
241962306a36Sopenharmony_ci		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
242062306a36Sopenharmony_ci			regofs = 0xfff;
242162306a36Sopenharmony_ci	}
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci	vga_w(cinfo->regbase, regofs + regnum, val);
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci/*** RGen() - read out one of the external/general registers ***/
242762306a36Sopenharmony_cistatic unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	unsigned long regofs = 0;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
243262306a36Sopenharmony_ci		/* Picasso II specific hack */
243362306a36Sopenharmony_ci/*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
243462306a36Sopenharmony_ci		  regnum == CL_VSSM2) */
243562306a36Sopenharmony_ci		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
243662306a36Sopenharmony_ci			regofs = 0xfff;
243762306a36Sopenharmony_ci	}
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	return vga_r(cinfo->regbase, regofs + regnum);
244062306a36Sopenharmony_ci}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
244362306a36Sopenharmony_cistatic void AttrOn(const struct cirrusfb_info *cinfo)
244462306a36Sopenharmony_ci{
244562306a36Sopenharmony_ci	assert(cinfo != NULL);
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
244862306a36Sopenharmony_ci		/* if we're just in "write value" mode, write back the */
244962306a36Sopenharmony_ci		/* same value as before to not modify anything */
245062306a36Sopenharmony_ci		vga_w(cinfo->regbase, VGA_ATT_IW,
245162306a36Sopenharmony_ci		      vga_r(cinfo->regbase, VGA_ATT_R));
245262306a36Sopenharmony_ci	}
245362306a36Sopenharmony_ci	/* turn on video bit */
245462306a36Sopenharmony_ci/*      vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
245562306a36Sopenharmony_ci	vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	/* dummy write on Reg0 to be on "write index" mode next time */
245862306a36Sopenharmony_ci	vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci/*** WHDR() - write into the Hidden DAC register ***/
246262306a36Sopenharmony_ci/* as the HDR is the only extension register that requires special treatment
246362306a36Sopenharmony_ci * (the other extension registers are accessible just like the "ordinary"
246462306a36Sopenharmony_ci * registers of their functional group) here is a specialized routine for
246562306a36Sopenharmony_ci * accessing the HDR
246662306a36Sopenharmony_ci */
246762306a36Sopenharmony_cistatic void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
246862306a36Sopenharmony_ci{
246962306a36Sopenharmony_ci	if (is_laguna(cinfo))
247062306a36Sopenharmony_ci		return;
247162306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
247262306a36Sopenharmony_ci		/* Klaus' hint for correct access to HDR on some boards */
247362306a36Sopenharmony_ci		/* first write 0 to pixel mask (3c6) */
247462306a36Sopenharmony_ci		WGen(cinfo, VGA_PEL_MSK, 0x00);
247562306a36Sopenharmony_ci		udelay(200);
247662306a36Sopenharmony_ci		/* next read dummy from pixel address (3c8) */
247762306a36Sopenharmony_ci		RGen(cinfo, VGA_PEL_IW);
247862306a36Sopenharmony_ci		udelay(200);
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_ci	/* now do the usual stuff to access the HDR */
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	RGen(cinfo, VGA_PEL_MSK);
248362306a36Sopenharmony_ci	udelay(200);
248462306a36Sopenharmony_ci	RGen(cinfo, VGA_PEL_MSK);
248562306a36Sopenharmony_ci	udelay(200);
248662306a36Sopenharmony_ci	RGen(cinfo, VGA_PEL_MSK);
248762306a36Sopenharmony_ci	udelay(200);
248862306a36Sopenharmony_ci	RGen(cinfo, VGA_PEL_MSK);
248962306a36Sopenharmony_ci	udelay(200);
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	WGen(cinfo, VGA_PEL_MSK, val);
249262306a36Sopenharmony_ci	udelay(200);
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
249562306a36Sopenharmony_ci		/* now first reset HDR access counter */
249662306a36Sopenharmony_ci		RGen(cinfo, VGA_PEL_IW);
249762306a36Sopenharmony_ci		udelay(200);
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci		/* and at the end, restore the mask value */
250062306a36Sopenharmony_ci		/* ## is this mask always 0xff? */
250162306a36Sopenharmony_ci		WGen(cinfo, VGA_PEL_MSK, 0xff);
250262306a36Sopenharmony_ci		udelay(200);
250362306a36Sopenharmony_ci	}
250462306a36Sopenharmony_ci}
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ci/*** WSFR() - write to the "special function register" (SFR) ***/
250762306a36Sopenharmony_cistatic void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
251062306a36Sopenharmony_ci	assert(cinfo->regbase != NULL);
251162306a36Sopenharmony_ci	cinfo->SFR = val;
251262306a36Sopenharmony_ci	z_writeb(val, cinfo->regbase + 0x8000);
251362306a36Sopenharmony_ci#endif
251462306a36Sopenharmony_ci}
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci/* The Picasso has a second register for switching the monitor bit */
251762306a36Sopenharmony_cistatic void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
251862306a36Sopenharmony_ci{
251962306a36Sopenharmony_ci#ifdef CONFIG_ZORRO
252062306a36Sopenharmony_ci	/* writing an arbitrary value to this one causes the monitor switcher */
252162306a36Sopenharmony_ci	/* to flip to Amiga display */
252262306a36Sopenharmony_ci	assert(cinfo->regbase != NULL);
252362306a36Sopenharmony_ci	cinfo->SFR = val;
252462306a36Sopenharmony_ci	z_writeb(val, cinfo->regbase + 0x9000);
252562306a36Sopenharmony_ci#endif
252662306a36Sopenharmony_ci}
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci/*** WClut - set CLUT entry (range: 0..63) ***/
252962306a36Sopenharmony_cistatic void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
253062306a36Sopenharmony_ci	    unsigned char green, unsigned char blue)
253162306a36Sopenharmony_ci{
253262306a36Sopenharmony_ci	unsigned int data = VGA_PEL_D;
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	/* address write mode register is not translated.. */
253562306a36Sopenharmony_ci	vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
253862306a36Sopenharmony_ci	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 ||
253962306a36Sopenharmony_ci	    cinfo->btype == BT_SD64 || is_laguna(cinfo)) {
254062306a36Sopenharmony_ci		/* but DAC data register IS, at least for Picasso II */
254162306a36Sopenharmony_ci		if (cinfo->btype == BT_PICASSO)
254262306a36Sopenharmony_ci			data += 0xfff;
254362306a36Sopenharmony_ci		vga_w(cinfo->regbase, data, red);
254462306a36Sopenharmony_ci		vga_w(cinfo->regbase, data, green);
254562306a36Sopenharmony_ci		vga_w(cinfo->regbase, data, blue);
254662306a36Sopenharmony_ci	} else {
254762306a36Sopenharmony_ci		vga_w(cinfo->regbase, data, blue);
254862306a36Sopenharmony_ci		vga_w(cinfo->regbase, data, green);
254962306a36Sopenharmony_ci		vga_w(cinfo->regbase, data, red);
255062306a36Sopenharmony_ci	}
255162306a36Sopenharmony_ci}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci#if 0
255462306a36Sopenharmony_ci/*** RClut - read CLUT entry (range 0..63) ***/
255562306a36Sopenharmony_cistatic void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
255662306a36Sopenharmony_ci	    unsigned char *green, unsigned char *blue)
255762306a36Sopenharmony_ci{
255862306a36Sopenharmony_ci	unsigned int data = VGA_PEL_D;
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
256362306a36Sopenharmony_ci	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
256462306a36Sopenharmony_ci		if (cinfo->btype == BT_PICASSO)
256562306a36Sopenharmony_ci			data += 0xfff;
256662306a36Sopenharmony_ci		*red = vga_r(cinfo->regbase, data);
256762306a36Sopenharmony_ci		*green = vga_r(cinfo->regbase, data);
256862306a36Sopenharmony_ci		*blue = vga_r(cinfo->regbase, data);
256962306a36Sopenharmony_ci	} else {
257062306a36Sopenharmony_ci		*blue = vga_r(cinfo->regbase, data);
257162306a36Sopenharmony_ci		*green = vga_r(cinfo->regbase, data);
257262306a36Sopenharmony_ci		*red = vga_r(cinfo->regbase, data);
257362306a36Sopenharmony_ci	}
257462306a36Sopenharmony_ci}
257562306a36Sopenharmony_ci#endif
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci/*******************************************************************
257862306a36Sopenharmony_ci	cirrusfb_WaitBLT()
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	Wait for the BitBLT engine to complete a possible earlier job
258162306a36Sopenharmony_ci*********************************************************************/
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci/* FIXME: use interrupts instead */
258462306a36Sopenharmony_cistatic void cirrusfb_WaitBLT(u8 __iomem *regbase)
258562306a36Sopenharmony_ci{
258662306a36Sopenharmony_ci	while (vga_rgfx(regbase, CL_GR31) & 0x08)
258762306a36Sopenharmony_ci		cpu_relax();
258862306a36Sopenharmony_ci}
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci/*******************************************************************
259162306a36Sopenharmony_ci	cirrusfb_BitBLT()
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	perform accelerated "scrolling"
259462306a36Sopenharmony_ci********************************************************************/
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_cistatic void cirrusfb_set_blitter(u8 __iomem *regbase,
259762306a36Sopenharmony_ci			    u_short nwidth, u_short nheight,
259862306a36Sopenharmony_ci			    u_long nsrc, u_long ndest,
259962306a36Sopenharmony_ci			    u_short bltmode, u_short line_length)
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	/* pitch: set to line_length */
260362306a36Sopenharmony_ci	/* dest pitch low */
260462306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR24, line_length & 0xff);
260562306a36Sopenharmony_ci	/* dest pitch hi */
260662306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR25, line_length >> 8);
260762306a36Sopenharmony_ci	/* source pitch low */
260862306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR26, line_length & 0xff);
260962306a36Sopenharmony_ci	/* source pitch hi */
261062306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR27, line_length >> 8);
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	/* BLT width: actual number of pixels - 1 */
261362306a36Sopenharmony_ci	/* BLT width low */
261462306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
261562306a36Sopenharmony_ci	/* BLT width hi */
261662306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR21, nwidth >> 8);
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci	/* BLT height: actual number of lines -1 */
261962306a36Sopenharmony_ci	/* BLT height low */
262062306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR22, nheight & 0xff);
262162306a36Sopenharmony_ci	/* BLT width hi */
262262306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR23, nheight >> 8);
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci	/* BLT destination */
262562306a36Sopenharmony_ci	/* BLT dest low */
262662306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
262762306a36Sopenharmony_ci	/* BLT dest mid */
262862306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
262962306a36Sopenharmony_ci	/* BLT dest hi */
263062306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ci	/* BLT source */
263362306a36Sopenharmony_ci	/* BLT src low */
263462306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
263562306a36Sopenharmony_ci	/* BLT src mid */
263662306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
263762306a36Sopenharmony_ci	/* BLT src hi */
263862306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	/* BLT mode */
264162306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR30, bltmode);	/* BLT mode */
264262306a36Sopenharmony_ci
264362306a36Sopenharmony_ci	/* BLT ROP: SrcCopy */
264462306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR32, 0x0d);	/* BLT ROP */
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	/* and finally: GO! */
264762306a36Sopenharmony_ci	vga_wgfx(regbase, CL_GR31, 0x02);	/* BLT Start/status */
264862306a36Sopenharmony_ci}
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci/*******************************************************************
265162306a36Sopenharmony_ci	cirrusfb_BitBLT()
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	perform accelerated "scrolling"
265462306a36Sopenharmony_ci********************************************************************/
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_cistatic void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
265762306a36Sopenharmony_ci			    u_short curx, u_short cury,
265862306a36Sopenharmony_ci			    u_short destx, u_short desty,
265962306a36Sopenharmony_ci			    u_short width, u_short height,
266062306a36Sopenharmony_ci			    u_short line_length)
266162306a36Sopenharmony_ci{
266262306a36Sopenharmony_ci	u_short nwidth = width - 1;
266362306a36Sopenharmony_ci	u_short nheight = height - 1;
266462306a36Sopenharmony_ci	u_long nsrc, ndest;
266562306a36Sopenharmony_ci	u_char bltmode;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	bltmode = 0x00;
266862306a36Sopenharmony_ci	/* if source adr < dest addr, do the Blt backwards */
266962306a36Sopenharmony_ci	if (cury <= desty) {
267062306a36Sopenharmony_ci		if (cury == desty) {
267162306a36Sopenharmony_ci			/* if src and dest are on the same line, check x */
267262306a36Sopenharmony_ci			if (curx < destx)
267362306a36Sopenharmony_ci				bltmode |= 0x01;
267462306a36Sopenharmony_ci		} else
267562306a36Sopenharmony_ci			bltmode |= 0x01;
267662306a36Sopenharmony_ci	}
267762306a36Sopenharmony_ci	/* standard case: forward blitting */
267862306a36Sopenharmony_ci	nsrc = (cury * line_length) + curx;
267962306a36Sopenharmony_ci	ndest = (desty * line_length) + destx;
268062306a36Sopenharmony_ci	if (bltmode) {
268162306a36Sopenharmony_ci		/* this means start addresses are at the end,
268262306a36Sopenharmony_ci		 * counting backwards
268362306a36Sopenharmony_ci		 */
268462306a36Sopenharmony_ci		nsrc += nheight * line_length + nwidth;
268562306a36Sopenharmony_ci		ndest += nheight * line_length + nwidth;
268662306a36Sopenharmony_ci	}
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	cirrusfb_WaitBLT(regbase);
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	cirrusfb_set_blitter(regbase, nwidth, nheight,
269162306a36Sopenharmony_ci			    nsrc, ndest, bltmode, line_length);
269262306a36Sopenharmony_ci}
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci/*******************************************************************
269562306a36Sopenharmony_ci	cirrusfb_RectFill()
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	perform accelerated rectangle fill
269862306a36Sopenharmony_ci********************************************************************/
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_cistatic void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
270162306a36Sopenharmony_ci		     u_short x, u_short y, u_short width, u_short height,
270262306a36Sopenharmony_ci		     u32 fg_color, u32 bg_color, u_short line_length,
270362306a36Sopenharmony_ci		     u_char blitmode)
270462306a36Sopenharmony_ci{
270562306a36Sopenharmony_ci	u_long ndest = (y * line_length) + x;
270662306a36Sopenharmony_ci	u_char op;
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	cirrusfb_WaitBLT(regbase);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	/* This is a ColorExpand Blt, using the */
271162306a36Sopenharmony_ci	/* same color for foreground and background */
271262306a36Sopenharmony_ci	vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color);
271362306a36Sopenharmony_ci	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	op = 0x80;
271662306a36Sopenharmony_ci	if (bits_per_pixel >= 16) {
271762306a36Sopenharmony_ci		vga_wgfx(regbase, CL_GR10, bg_color >> 8);
271862306a36Sopenharmony_ci		vga_wgfx(regbase, CL_GR11, fg_color >> 8);
271962306a36Sopenharmony_ci		op = 0x90;
272062306a36Sopenharmony_ci	}
272162306a36Sopenharmony_ci	if (bits_per_pixel >= 24) {
272262306a36Sopenharmony_ci		vga_wgfx(regbase, CL_GR12, bg_color >> 16);
272362306a36Sopenharmony_ci		vga_wgfx(regbase, CL_GR13, fg_color >> 16);
272462306a36Sopenharmony_ci		op = 0xa0;
272562306a36Sopenharmony_ci	}
272662306a36Sopenharmony_ci	if (bits_per_pixel == 32) {
272762306a36Sopenharmony_ci		vga_wgfx(regbase, CL_GR14, bg_color >> 24);
272862306a36Sopenharmony_ci		vga_wgfx(regbase, CL_GR15, fg_color >> 24);
272962306a36Sopenharmony_ci		op = 0xb0;
273062306a36Sopenharmony_ci	}
273162306a36Sopenharmony_ci	cirrusfb_set_blitter(regbase, width - 1, height - 1,
273262306a36Sopenharmony_ci			    0, ndest, op | blitmode, line_length);
273362306a36Sopenharmony_ci}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci/**************************************************************************
273662306a36Sopenharmony_ci * bestclock() - determine closest possible clock lower(?) than the
273762306a36Sopenharmony_ci * desired pixel clock
273862306a36Sopenharmony_ci **************************************************************************/
273962306a36Sopenharmony_cistatic void bestclock(long freq, int *nom, int *den, int *div)
274062306a36Sopenharmony_ci{
274162306a36Sopenharmony_ci	int n, d;
274262306a36Sopenharmony_ci	long h, diff;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	assert(nom != NULL);
274562306a36Sopenharmony_ci	assert(den != NULL);
274662306a36Sopenharmony_ci	assert(div != NULL);
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	*nom = 0;
274962306a36Sopenharmony_ci	*den = 0;
275062306a36Sopenharmony_ci	*div = 0;
275162306a36Sopenharmony_ci
275262306a36Sopenharmony_ci	if (freq < 8000)
275362306a36Sopenharmony_ci		freq = 8000;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	diff = freq;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	for (n = 32; n < 128; n++) {
275862306a36Sopenharmony_ci		int s = 0;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci		d = (14318 * n) / freq;
276162306a36Sopenharmony_ci		if ((d >= 7) && (d <= 63)) {
276262306a36Sopenharmony_ci			int temp = d;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci			if (temp > 31) {
276562306a36Sopenharmony_ci				s = 1;
276662306a36Sopenharmony_ci				temp >>= 1;
276762306a36Sopenharmony_ci			}
276862306a36Sopenharmony_ci			h = ((14318 * n) / temp) >> s;
276962306a36Sopenharmony_ci			h = h > freq ? h - freq : freq - h;
277062306a36Sopenharmony_ci			if (h < diff) {
277162306a36Sopenharmony_ci				diff = h;
277262306a36Sopenharmony_ci				*nom = n;
277362306a36Sopenharmony_ci				*den = temp;
277462306a36Sopenharmony_ci				*div = s;
277562306a36Sopenharmony_ci			}
277662306a36Sopenharmony_ci		}
277762306a36Sopenharmony_ci		d++;
277862306a36Sopenharmony_ci		if ((d >= 7) && (d <= 63)) {
277962306a36Sopenharmony_ci			if (d > 31) {
278062306a36Sopenharmony_ci				s = 1;
278162306a36Sopenharmony_ci				d >>= 1;
278262306a36Sopenharmony_ci			}
278362306a36Sopenharmony_ci			h = ((14318 * n) / d) >> s;
278462306a36Sopenharmony_ci			h = h > freq ? h - freq : freq - h;
278562306a36Sopenharmony_ci			if (h < diff) {
278662306a36Sopenharmony_ci				diff = h;
278762306a36Sopenharmony_ci				*nom = n;
278862306a36Sopenharmony_ci				*den = d;
278962306a36Sopenharmony_ci				*div = s;
279062306a36Sopenharmony_ci			}
279162306a36Sopenharmony_ci		}
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci/* -------------------------------------------------------------------------
279662306a36Sopenharmony_ci *
279762306a36Sopenharmony_ci * debugging functions
279862306a36Sopenharmony_ci *
279962306a36Sopenharmony_ci * -------------------------------------------------------------------------
280062306a36Sopenharmony_ci */
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_ci/*
280562306a36Sopenharmony_ci * cirrusfb_dbg_print_regs
280662306a36Sopenharmony_ci * @regbase: If using newmmio, the newmmio base address, otherwise %NULL
280762306a36Sopenharmony_ci * @reg_class: type of registers to read: %CRT, or %SEQ
280862306a36Sopenharmony_ci *
280962306a36Sopenharmony_ci * DESCRIPTION:
281062306a36Sopenharmony_ci * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
281162306a36Sopenharmony_ci * old-style I/O ports are queried for information, otherwise MMIO is
281262306a36Sopenharmony_ci * used at the given @base address to query the information.
281362306a36Sopenharmony_ci */
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_cistatic void cirrusfb_dbg_print_regs(struct fb_info *info,
281662306a36Sopenharmony_ci				    caddr_t regbase,
281762306a36Sopenharmony_ci				    enum cirrusfb_dbg_reg_class reg_class, ...)
281862306a36Sopenharmony_ci{
281962306a36Sopenharmony_ci	va_list list;
282062306a36Sopenharmony_ci	unsigned char val = 0;
282162306a36Sopenharmony_ci	unsigned reg;
282262306a36Sopenharmony_ci	char *name;
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	va_start(list, reg_class);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	name = va_arg(list, char *);
282762306a36Sopenharmony_ci	while (name != NULL) {
282862306a36Sopenharmony_ci		reg = va_arg(list, int);
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci		switch (reg_class) {
283162306a36Sopenharmony_ci		case CRT:
283262306a36Sopenharmony_ci			val = vga_rcrt(regbase, (unsigned char) reg);
283362306a36Sopenharmony_ci			break;
283462306a36Sopenharmony_ci		case SEQ:
283562306a36Sopenharmony_ci			val = vga_rseq(regbase, (unsigned char) reg);
283662306a36Sopenharmony_ci			break;
283762306a36Sopenharmony_ci		default:
283862306a36Sopenharmony_ci			/* should never occur */
283962306a36Sopenharmony_ci			assert(false);
284062306a36Sopenharmony_ci			break;
284162306a36Sopenharmony_ci		}
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci		dev_dbg(info->device, "%8s = 0x%02X\n", name, val);
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci		name = va_arg(list, char *);
284662306a36Sopenharmony_ci	}
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	va_end(list);
284962306a36Sopenharmony_ci}
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci/*
285262306a36Sopenharmony_ci * cirrusfb_dbg_reg_dump
285362306a36Sopenharmony_ci * @base: If using newmmio, the newmmio base address, otherwise %NULL
285462306a36Sopenharmony_ci *
285562306a36Sopenharmony_ci * DESCRIPTION:
285662306a36Sopenharmony_ci * Dumps a list of interesting VGA and CIRRUSFB registers.  If @base is %NULL,
285762306a36Sopenharmony_ci * old-style I/O ports are queried for information, otherwise MMIO is
285862306a36Sopenharmony_ci * used at the given @base address to query the information.
285962306a36Sopenharmony_ci */
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_cistatic void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
286262306a36Sopenharmony_ci{
286362306a36Sopenharmony_ci	dev_dbg(info->device, "VGA CRTC register dump:\n");
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	cirrusfb_dbg_print_regs(info, regbase, CRT,
286662306a36Sopenharmony_ci			   "CR00", 0x00,
286762306a36Sopenharmony_ci			   "CR01", 0x01,
286862306a36Sopenharmony_ci			   "CR02", 0x02,
286962306a36Sopenharmony_ci			   "CR03", 0x03,
287062306a36Sopenharmony_ci			   "CR04", 0x04,
287162306a36Sopenharmony_ci			   "CR05", 0x05,
287262306a36Sopenharmony_ci			   "CR06", 0x06,
287362306a36Sopenharmony_ci			   "CR07", 0x07,
287462306a36Sopenharmony_ci			   "CR08", 0x08,
287562306a36Sopenharmony_ci			   "CR09", 0x09,
287662306a36Sopenharmony_ci			   "CR0A", 0x0A,
287762306a36Sopenharmony_ci			   "CR0B", 0x0B,
287862306a36Sopenharmony_ci			   "CR0C", 0x0C,
287962306a36Sopenharmony_ci			   "CR0D", 0x0D,
288062306a36Sopenharmony_ci			   "CR0E", 0x0E,
288162306a36Sopenharmony_ci			   "CR0F", 0x0F,
288262306a36Sopenharmony_ci			   "CR10", 0x10,
288362306a36Sopenharmony_ci			   "CR11", 0x11,
288462306a36Sopenharmony_ci			   "CR12", 0x12,
288562306a36Sopenharmony_ci			   "CR13", 0x13,
288662306a36Sopenharmony_ci			   "CR14", 0x14,
288762306a36Sopenharmony_ci			   "CR15", 0x15,
288862306a36Sopenharmony_ci			   "CR16", 0x16,
288962306a36Sopenharmony_ci			   "CR17", 0x17,
289062306a36Sopenharmony_ci			   "CR18", 0x18,
289162306a36Sopenharmony_ci			   "CR22", 0x22,
289262306a36Sopenharmony_ci			   "CR24", 0x24,
289362306a36Sopenharmony_ci			   "CR26", 0x26,
289462306a36Sopenharmony_ci			   "CR2D", 0x2D,
289562306a36Sopenharmony_ci			   "CR2E", 0x2E,
289662306a36Sopenharmony_ci			   "CR2F", 0x2F,
289762306a36Sopenharmony_ci			   "CR30", 0x30,
289862306a36Sopenharmony_ci			   "CR31", 0x31,
289962306a36Sopenharmony_ci			   "CR32", 0x32,
290062306a36Sopenharmony_ci			   "CR33", 0x33,
290162306a36Sopenharmony_ci			   "CR34", 0x34,
290262306a36Sopenharmony_ci			   "CR35", 0x35,
290362306a36Sopenharmony_ci			   "CR36", 0x36,
290462306a36Sopenharmony_ci			   "CR37", 0x37,
290562306a36Sopenharmony_ci			   "CR38", 0x38,
290662306a36Sopenharmony_ci			   "CR39", 0x39,
290762306a36Sopenharmony_ci			   "CR3A", 0x3A,
290862306a36Sopenharmony_ci			   "CR3B", 0x3B,
290962306a36Sopenharmony_ci			   "CR3C", 0x3C,
291062306a36Sopenharmony_ci			   "CR3D", 0x3D,
291162306a36Sopenharmony_ci			   "CR3E", 0x3E,
291262306a36Sopenharmony_ci			   "CR3F", 0x3F,
291362306a36Sopenharmony_ci			   NULL);
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	dev_dbg(info->device, "\n");
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	dev_dbg(info->device, "VGA SEQ register dump:\n");
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	cirrusfb_dbg_print_regs(info, regbase, SEQ,
292062306a36Sopenharmony_ci			   "SR00", 0x00,
292162306a36Sopenharmony_ci			   "SR01", 0x01,
292262306a36Sopenharmony_ci			   "SR02", 0x02,
292362306a36Sopenharmony_ci			   "SR03", 0x03,
292462306a36Sopenharmony_ci			   "SR04", 0x04,
292562306a36Sopenharmony_ci			   "SR08", 0x08,
292662306a36Sopenharmony_ci			   "SR09", 0x09,
292762306a36Sopenharmony_ci			   "SR0A", 0x0A,
292862306a36Sopenharmony_ci			   "SR0B", 0x0B,
292962306a36Sopenharmony_ci			   "SR0D", 0x0D,
293062306a36Sopenharmony_ci			   "SR10", 0x10,
293162306a36Sopenharmony_ci			   "SR11", 0x11,
293262306a36Sopenharmony_ci			   "SR12", 0x12,
293362306a36Sopenharmony_ci			   "SR13", 0x13,
293462306a36Sopenharmony_ci			   "SR14", 0x14,
293562306a36Sopenharmony_ci			   "SR15", 0x15,
293662306a36Sopenharmony_ci			   "SR16", 0x16,
293762306a36Sopenharmony_ci			   "SR17", 0x17,
293862306a36Sopenharmony_ci			   "SR18", 0x18,
293962306a36Sopenharmony_ci			   "SR19", 0x19,
294062306a36Sopenharmony_ci			   "SR1A", 0x1A,
294162306a36Sopenharmony_ci			   "SR1B", 0x1B,
294262306a36Sopenharmony_ci			   "SR1C", 0x1C,
294362306a36Sopenharmony_ci			   "SR1D", 0x1D,
294462306a36Sopenharmony_ci			   "SR1E", 0x1E,
294562306a36Sopenharmony_ci			   "SR1F", 0x1F,
294662306a36Sopenharmony_ci			   NULL);
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci	dev_dbg(info->device, "\n");
294962306a36Sopenharmony_ci}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci#endif				/* CIRRUSFB_DEBUG */
295262306a36Sopenharmony_ci
2953