18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Contributors (thanks, all!)
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *	David Eger:
98c2ecf20Sopenharmony_ci *	Overhaul for Linux 2.6
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *      Jeff Rugen:
128c2ecf20Sopenharmony_ci *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
138c2ecf20Sopenharmony_ci *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *	Geert Uytterhoeven:
168c2ecf20Sopenharmony_ci *	Excellent code review.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *	Lars Hecking:
198c2ecf20Sopenharmony_ci *	Amiga updates and testing.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Original cirrusfb author:  Frank Neumann
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * Based on retz3fb.c and cirrusfb.c:
248c2ecf20Sopenharmony_ci *      Copyright (C) 1997 Jes Sorensen
258c2ecf20Sopenharmony_ci *      Copyright (C) 1996 Frank Neumann
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci ***************************************************************
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * Format this code with GNU indent '-kr -i8 -pcs' options.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
328c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
338c2ecf20Sopenharmony_ci * for more details.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/module.h>
388c2ecf20Sopenharmony_ci#include <linux/kernel.h>
398c2ecf20Sopenharmony_ci#include <linux/errno.h>
408c2ecf20Sopenharmony_ci#include <linux/string.h>
418c2ecf20Sopenharmony_ci#include <linux/mm.h>
428c2ecf20Sopenharmony_ci#include <linux/delay.h>
438c2ecf20Sopenharmony_ci#include <linux/fb.h>
448c2ecf20Sopenharmony_ci#include <linux/init.h>
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
478c2ecf20Sopenharmony_ci#include <linux/zorro.h>
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
508c2ecf20Sopenharmony_ci#include <linux/pci.h>
518c2ecf20Sopenharmony_ci#endif
528c2ecf20Sopenharmony_ci#ifdef CONFIG_AMIGA
538c2ecf20Sopenharmony_ci#include <asm/amigahw.h>
548c2ecf20Sopenharmony_ci#endif
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#include <video/vga.h>
578c2ecf20Sopenharmony_ci#include <video/cirrus.h>
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/*****************************************************************
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * debugging and utility macros
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* disable runtime assertions? */
668c2ecf20Sopenharmony_ci/* #define CIRRUSFB_NDEBUG */
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* debugging assertions */
698c2ecf20Sopenharmony_ci#ifndef CIRRUSFB_NDEBUG
708c2ecf20Sopenharmony_ci#define assert(expr) \
718c2ecf20Sopenharmony_ci	if (!(expr)) { \
728c2ecf20Sopenharmony_ci		printk("Assertion failed! %s,%s,%s,line=%d\n", \
738c2ecf20Sopenharmony_ci		#expr, __FILE__, __func__, __LINE__); \
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci#else
768c2ecf20Sopenharmony_ci#define assert(expr)
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define MB_ (1024 * 1024)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*****************************************************************
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * chipset information
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* board types */
888c2ecf20Sopenharmony_cienum cirrus_board {
898c2ecf20Sopenharmony_ci	BT_NONE = 0,
908c2ecf20Sopenharmony_ci	BT_SD64,	/* GD5434 */
918c2ecf20Sopenharmony_ci	BT_PICCOLO,	/* GD5426 */
928c2ecf20Sopenharmony_ci	BT_PICASSO,	/* GD5426 or GD5428 */
938c2ecf20Sopenharmony_ci	BT_SPECTRUM,	/* GD5426 or GD5428 */
948c2ecf20Sopenharmony_ci	BT_PICASSO4,	/* GD5446 */
958c2ecf20Sopenharmony_ci	BT_ALPINE,	/* GD543x/4x */
968c2ecf20Sopenharmony_ci	BT_GD5480,
978c2ecf20Sopenharmony_ci	BT_LAGUNA,	/* GD5462/64 */
988c2ecf20Sopenharmony_ci	BT_LAGUNAB,	/* GD5465 */
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/*
1028c2ecf20Sopenharmony_ci * per-board-type information, used for enumerating and abstracting
1038c2ecf20Sopenharmony_ci * chip-specific information
1048c2ecf20Sopenharmony_ci * NOTE: MUST be in the same order as enum cirrus_board in order to
1058c2ecf20Sopenharmony_ci * use direct indexing on this array
1068c2ecf20Sopenharmony_ci * NOTE: '__initdata' cannot be used as some of this info
1078c2ecf20Sopenharmony_ci * is required at runtime.  Maybe separate into an init-only and
1088c2ecf20Sopenharmony_ci * a run-time table?
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_cistatic const struct cirrusfb_board_info_rec {
1118c2ecf20Sopenharmony_ci	char *name;		/* ASCII name of chipset */
1128c2ecf20Sopenharmony_ci	long maxclock[5];		/* maximum video clock */
1138c2ecf20Sopenharmony_ci	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
1148c2ecf20Sopenharmony_ci	bool init_sr07 : 1; /* init SR07 during init_vgachip() */
1158c2ecf20Sopenharmony_ci	bool init_sr1f : 1; /* write SR1F during init_vgachip() */
1168c2ecf20Sopenharmony_ci	/* construct bit 19 of screen start address */
1178c2ecf20Sopenharmony_ci	bool scrn_start_bit19 : 1;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* initial SR07 value, then for each mode */
1208c2ecf20Sopenharmony_ci	unsigned char sr07;
1218c2ecf20Sopenharmony_ci	unsigned char sr07_1bpp;
1228c2ecf20Sopenharmony_ci	unsigned char sr07_1bpp_mux;
1238c2ecf20Sopenharmony_ci	unsigned char sr07_8bpp;
1248c2ecf20Sopenharmony_ci	unsigned char sr07_8bpp_mux;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	unsigned char sr1f;	/* SR1F VGA initial register value */
1278c2ecf20Sopenharmony_ci} cirrusfb_board_info[] = {
1288c2ecf20Sopenharmony_ci	[BT_SD64] = {
1298c2ecf20Sopenharmony_ci		.name			= "CL SD64",
1308c2ecf20Sopenharmony_ci		.maxclock		= {
1318c2ecf20Sopenharmony_ci			/* guess */
1328c2ecf20Sopenharmony_ci			/* the SD64/P4 have a higher max. videoclock */
1338c2ecf20Sopenharmony_ci			135100, 135100, 85500, 85500, 0
1348c2ecf20Sopenharmony_ci		},
1358c2ecf20Sopenharmony_ci		.init_sr07		= true,
1368c2ecf20Sopenharmony_ci		.init_sr1f		= true,
1378c2ecf20Sopenharmony_ci		.scrn_start_bit19	= true,
1388c2ecf20Sopenharmony_ci		.sr07			= 0xF0,
1398c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0xF0,
1408c2ecf20Sopenharmony_ci		.sr07_1bpp_mux		= 0xF6,
1418c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0xF1,
1428c2ecf20Sopenharmony_ci		.sr07_8bpp_mux		= 0xF7,
1438c2ecf20Sopenharmony_ci		.sr1f			= 0x1E
1448c2ecf20Sopenharmony_ci	},
1458c2ecf20Sopenharmony_ci	[BT_PICCOLO] = {
1468c2ecf20Sopenharmony_ci		.name			= "CL Piccolo",
1478c2ecf20Sopenharmony_ci		.maxclock		= {
1488c2ecf20Sopenharmony_ci			/* guess */
1498c2ecf20Sopenharmony_ci			90000, 90000, 90000, 90000, 90000
1508c2ecf20Sopenharmony_ci		},
1518c2ecf20Sopenharmony_ci		.init_sr07		= true,
1528c2ecf20Sopenharmony_ci		.init_sr1f		= true,
1538c2ecf20Sopenharmony_ci		.scrn_start_bit19	= false,
1548c2ecf20Sopenharmony_ci		.sr07			= 0x80,
1558c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0x80,
1568c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0x81,
1578c2ecf20Sopenharmony_ci		.sr1f			= 0x22
1588c2ecf20Sopenharmony_ci	},
1598c2ecf20Sopenharmony_ci	[BT_PICASSO] = {
1608c2ecf20Sopenharmony_ci		.name			= "CL Picasso",
1618c2ecf20Sopenharmony_ci		.maxclock		= {
1628c2ecf20Sopenharmony_ci			/* guess */
1638c2ecf20Sopenharmony_ci			90000, 90000, 90000, 90000, 90000
1648c2ecf20Sopenharmony_ci		},
1658c2ecf20Sopenharmony_ci		.init_sr07		= true,
1668c2ecf20Sopenharmony_ci		.init_sr1f		= true,
1678c2ecf20Sopenharmony_ci		.scrn_start_bit19	= false,
1688c2ecf20Sopenharmony_ci		.sr07			= 0x20,
1698c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0x20,
1708c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0x21,
1718c2ecf20Sopenharmony_ci		.sr1f			= 0x22
1728c2ecf20Sopenharmony_ci	},
1738c2ecf20Sopenharmony_ci	[BT_SPECTRUM] = {
1748c2ecf20Sopenharmony_ci		.name			= "CL Spectrum",
1758c2ecf20Sopenharmony_ci		.maxclock		= {
1768c2ecf20Sopenharmony_ci			/* guess */
1778c2ecf20Sopenharmony_ci			90000, 90000, 90000, 90000, 90000
1788c2ecf20Sopenharmony_ci		},
1798c2ecf20Sopenharmony_ci		.init_sr07		= true,
1808c2ecf20Sopenharmony_ci		.init_sr1f		= true,
1818c2ecf20Sopenharmony_ci		.scrn_start_bit19	= false,
1828c2ecf20Sopenharmony_ci		.sr07			= 0x80,
1838c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0x80,
1848c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0x81,
1858c2ecf20Sopenharmony_ci		.sr1f			= 0x22
1868c2ecf20Sopenharmony_ci	},
1878c2ecf20Sopenharmony_ci	[BT_PICASSO4] = {
1888c2ecf20Sopenharmony_ci		.name			= "CL Picasso4",
1898c2ecf20Sopenharmony_ci		.maxclock		= {
1908c2ecf20Sopenharmony_ci			135100, 135100, 85500, 85500, 0
1918c2ecf20Sopenharmony_ci		},
1928c2ecf20Sopenharmony_ci		.init_sr07		= true,
1938c2ecf20Sopenharmony_ci		.init_sr1f		= false,
1948c2ecf20Sopenharmony_ci		.scrn_start_bit19	= true,
1958c2ecf20Sopenharmony_ci		.sr07			= 0xA0,
1968c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0xA0,
1978c2ecf20Sopenharmony_ci		.sr07_1bpp_mux		= 0xA6,
1988c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0xA1,
1998c2ecf20Sopenharmony_ci		.sr07_8bpp_mux		= 0xA7,
2008c2ecf20Sopenharmony_ci		.sr1f			= 0
2018c2ecf20Sopenharmony_ci	},
2028c2ecf20Sopenharmony_ci	[BT_ALPINE] = {
2038c2ecf20Sopenharmony_ci		.name			= "CL Alpine",
2048c2ecf20Sopenharmony_ci		.maxclock		= {
2058c2ecf20Sopenharmony_ci			/* for the GD5430.  GD5446 can do more... */
2068c2ecf20Sopenharmony_ci			85500, 85500, 50000, 28500, 0
2078c2ecf20Sopenharmony_ci		},
2088c2ecf20Sopenharmony_ci		.init_sr07		= true,
2098c2ecf20Sopenharmony_ci		.init_sr1f		= true,
2108c2ecf20Sopenharmony_ci		.scrn_start_bit19	= true,
2118c2ecf20Sopenharmony_ci		.sr07			= 0xA0,
2128c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0xA0,
2138c2ecf20Sopenharmony_ci		.sr07_1bpp_mux		= 0xA6,
2148c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0xA1,
2158c2ecf20Sopenharmony_ci		.sr07_8bpp_mux		= 0xA7,
2168c2ecf20Sopenharmony_ci		.sr1f			= 0x1C
2178c2ecf20Sopenharmony_ci	},
2188c2ecf20Sopenharmony_ci	[BT_GD5480] = {
2198c2ecf20Sopenharmony_ci		.name			= "CL GD5480",
2208c2ecf20Sopenharmony_ci		.maxclock		= {
2218c2ecf20Sopenharmony_ci			135100, 200000, 200000, 135100, 135100
2228c2ecf20Sopenharmony_ci		},
2238c2ecf20Sopenharmony_ci		.init_sr07		= true,
2248c2ecf20Sopenharmony_ci		.init_sr1f		= true,
2258c2ecf20Sopenharmony_ci		.scrn_start_bit19	= true,
2268c2ecf20Sopenharmony_ci		.sr07			= 0x10,
2278c2ecf20Sopenharmony_ci		.sr07_1bpp		= 0x11,
2288c2ecf20Sopenharmony_ci		.sr07_8bpp		= 0x11,
2298c2ecf20Sopenharmony_ci		.sr1f			= 0x1C
2308c2ecf20Sopenharmony_ci	},
2318c2ecf20Sopenharmony_ci	[BT_LAGUNA] = {
2328c2ecf20Sopenharmony_ci		.name			= "CL Laguna",
2338c2ecf20Sopenharmony_ci		.maxclock		= {
2348c2ecf20Sopenharmony_ci			/* taken from X11 code */
2358c2ecf20Sopenharmony_ci			170000, 170000, 170000, 170000, 135100,
2368c2ecf20Sopenharmony_ci		},
2378c2ecf20Sopenharmony_ci		.init_sr07		= false,
2388c2ecf20Sopenharmony_ci		.init_sr1f		= false,
2398c2ecf20Sopenharmony_ci		.scrn_start_bit19	= true,
2408c2ecf20Sopenharmony_ci	},
2418c2ecf20Sopenharmony_ci	[BT_LAGUNAB] = {
2428c2ecf20Sopenharmony_ci		.name			= "CL Laguna AGP",
2438c2ecf20Sopenharmony_ci		.maxclock		= {
2448c2ecf20Sopenharmony_ci			/* taken from X11 code */
2458c2ecf20Sopenharmony_ci			170000, 250000, 170000, 170000, 135100,
2468c2ecf20Sopenharmony_ci		},
2478c2ecf20Sopenharmony_ci		.init_sr07		= false,
2488c2ecf20Sopenharmony_ci		.init_sr1f		= false,
2498c2ecf20Sopenharmony_ci		.scrn_start_bit19	= true,
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci};
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
2548c2ecf20Sopenharmony_ci#define CHIP(id, btype) \
2558c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic struct pci_device_id cirrusfb_pci_table[] = {
2588c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
2598c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64),
2608c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64),
2618c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
2628c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
2638c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
2648c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
2658c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
2668c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
2678c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
2688c2ecf20Sopenharmony_ci	CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/
2698c2ecf20Sopenharmony_ci	{ 0, }
2708c2ecf20Sopenharmony_ci};
2718c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
2728c2ecf20Sopenharmony_ci#undef CHIP
2738c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
2768c2ecf20Sopenharmony_cistruct zorrocl {
2778c2ecf20Sopenharmony_ci	enum cirrus_board type;	/* Board type */
2788c2ecf20Sopenharmony_ci	u32 regoffset;		/* Offset of registers in first Zorro device */
2798c2ecf20Sopenharmony_ci	u32 ramsize;		/* Size of video RAM in first Zorro device */
2808c2ecf20Sopenharmony_ci				/* If zero, use autoprobe on RAM device */
2818c2ecf20Sopenharmony_ci	u32 ramoffset;		/* Offset of video RAM in first Zorro device */
2828c2ecf20Sopenharmony_ci	zorro_id ramid;		/* Zorro ID of RAM device */
2838c2ecf20Sopenharmony_ci	zorro_id ramid2;	/* Zorro ID of optional second RAM device */
2848c2ecf20Sopenharmony_ci};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic const struct zorrocl zcl_sd64 = {
2878c2ecf20Sopenharmony_ci	.type		= BT_SD64,
2888c2ecf20Sopenharmony_ci	.ramid		= ZORRO_PROD_HELFRICH_SD64_RAM,
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic const struct zorrocl zcl_piccolo = {
2928c2ecf20Sopenharmony_ci	.type		= BT_PICCOLO,
2938c2ecf20Sopenharmony_ci	.ramid		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
2948c2ecf20Sopenharmony_ci};
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic const struct zorrocl zcl_picasso = {
2978c2ecf20Sopenharmony_ci	.type		= BT_PICASSO,
2988c2ecf20Sopenharmony_ci	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
2998c2ecf20Sopenharmony_ci};
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic const struct zorrocl zcl_spectrum = {
3028c2ecf20Sopenharmony_ci	.type		= BT_SPECTRUM,
3038c2ecf20Sopenharmony_ci	.ramid		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic const struct zorrocl zcl_picasso4_z3 = {
3078c2ecf20Sopenharmony_ci	.type		= BT_PICASSO4,
3088c2ecf20Sopenharmony_ci	.regoffset	= 0x00600000,
3098c2ecf20Sopenharmony_ci	.ramsize	= 4 * MB_,
3108c2ecf20Sopenharmony_ci	.ramoffset	= 0x01000000,	/* 0x02000000 for 64 MiB boards */
3118c2ecf20Sopenharmony_ci};
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic const struct zorrocl zcl_picasso4_z2 = {
3148c2ecf20Sopenharmony_ci	.type		= BT_PICASSO4,
3158c2ecf20Sopenharmony_ci	.regoffset	= 0x10000,
3168c2ecf20Sopenharmony_ci	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
3178c2ecf20Sopenharmony_ci	.ramid2		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2,
3188c2ecf20Sopenharmony_ci};
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic const struct zorro_device_id cirrusfb_zorro_table[] = {
3228c2ecf20Sopenharmony_ci	{
3238c2ecf20Sopenharmony_ci		.id		= ZORRO_PROD_HELFRICH_SD64_REG,
3248c2ecf20Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_sd64,
3258c2ecf20Sopenharmony_ci	}, {
3268c2ecf20Sopenharmony_ci		.id		= ZORRO_PROD_HELFRICH_PICCOLO_REG,
3278c2ecf20Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_piccolo,
3288c2ecf20Sopenharmony_ci	}, {
3298c2ecf20Sopenharmony_ci		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
3308c2ecf20Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_picasso,
3318c2ecf20Sopenharmony_ci	}, {
3328c2ecf20Sopenharmony_ci		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
3338c2ecf20Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_spectrum,
3348c2ecf20Sopenharmony_ci	}, {
3358c2ecf20Sopenharmony_ci		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
3368c2ecf20Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_picasso4_z3,
3378c2ecf20Sopenharmony_ci	}, {
3388c2ecf20Sopenharmony_ci		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG,
3398c2ecf20Sopenharmony_ci		.driver_data	= (unsigned long)&zcl_picasso4_z2,
3408c2ecf20Sopenharmony_ci	},
3418c2ecf20Sopenharmony_ci	{ 0 }
3428c2ecf20Sopenharmony_ci};
3438c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
3448c2ecf20Sopenharmony_ci#endif /* CONFIG_ZORRO */
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
3478c2ecf20Sopenharmony_cienum cirrusfb_dbg_reg_class {
3488c2ecf20Sopenharmony_ci	CRT,
3498c2ecf20Sopenharmony_ci	SEQ
3508c2ecf20Sopenharmony_ci};
3518c2ecf20Sopenharmony_ci#endif		/* CIRRUSFB_DEBUG */
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci/* info about board */
3548c2ecf20Sopenharmony_cistruct cirrusfb_info {
3558c2ecf20Sopenharmony_ci	u8 __iomem *regbase;
3568c2ecf20Sopenharmony_ci	u8 __iomem *laguna_mmio;
3578c2ecf20Sopenharmony_ci	enum cirrus_board btype;
3588c2ecf20Sopenharmony_ci	unsigned char SFR;	/* Shadow of special function register */
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	int multiplexing;
3618c2ecf20Sopenharmony_ci	int doubleVCLK;
3628c2ecf20Sopenharmony_ci	int blank_mode;
3638c2ecf20Sopenharmony_ci	u32 pseudo_palette[16];
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	void (*unmap)(struct fb_info *info);
3668c2ecf20Sopenharmony_ci};
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic bool noaccel;
3698c2ecf20Sopenharmony_cistatic char *mode_option = "640x480@60";
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/****************************************************************************/
3728c2ecf20Sopenharmony_ci/**** BEGIN PROTOTYPES ******************************************************/
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/*--- Interface used by the world ------------------------------------------*/
3758c2ecf20Sopenharmony_cistatic int cirrusfb_pan_display(struct fb_var_screeninfo *var,
3768c2ecf20Sopenharmony_ci				struct fb_info *info);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/*--- Internal routines ----------------------------------------------------*/
3798c2ecf20Sopenharmony_cistatic void init_vgachip(struct fb_info *info);
3808c2ecf20Sopenharmony_cistatic void switch_monitor(struct cirrusfb_info *cinfo, int on);
3818c2ecf20Sopenharmony_cistatic void WGen(const struct cirrusfb_info *cinfo,
3828c2ecf20Sopenharmony_ci		 int regnum, unsigned char val);
3838c2ecf20Sopenharmony_cistatic unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
3848c2ecf20Sopenharmony_cistatic void AttrOn(const struct cirrusfb_info *cinfo);
3858c2ecf20Sopenharmony_cistatic void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
3868c2ecf20Sopenharmony_cistatic void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
3878c2ecf20Sopenharmony_cistatic void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
3888c2ecf20Sopenharmony_cistatic void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
3898c2ecf20Sopenharmony_ci		  unsigned char red, unsigned char green, unsigned char blue);
3908c2ecf20Sopenharmony_ci#if 0
3918c2ecf20Sopenharmony_cistatic void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
3928c2ecf20Sopenharmony_ci		  unsigned char *red, unsigned char *green,
3938c2ecf20Sopenharmony_ci		  unsigned char *blue);
3948c2ecf20Sopenharmony_ci#endif
3958c2ecf20Sopenharmony_cistatic void cirrusfb_WaitBLT(u8 __iomem *regbase);
3968c2ecf20Sopenharmony_cistatic void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
3978c2ecf20Sopenharmony_ci			    u_short curx, u_short cury,
3988c2ecf20Sopenharmony_ci			    u_short destx, u_short desty,
3998c2ecf20Sopenharmony_ci			    u_short width, u_short height,
4008c2ecf20Sopenharmony_ci			    u_short line_length);
4018c2ecf20Sopenharmony_cistatic void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
4028c2ecf20Sopenharmony_ci			      u_short x, u_short y,
4038c2ecf20Sopenharmony_ci			      u_short width, u_short height,
4048c2ecf20Sopenharmony_ci			      u32 fg_color, u32 bg_color,
4058c2ecf20Sopenharmony_ci			      u_short line_length, u_char blitmode);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void bestclock(long freq, int *nom, int *den, int *div);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
4108c2ecf20Sopenharmony_cistatic void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
4118c2ecf20Sopenharmony_cistatic void cirrusfb_dbg_print_regs(struct fb_info *info,
4128c2ecf20Sopenharmony_ci				    caddr_t regbase,
4138c2ecf20Sopenharmony_ci				    enum cirrusfb_dbg_reg_class reg_class, ...);
4148c2ecf20Sopenharmony_ci#endif /* CIRRUSFB_DEBUG */
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci/*** END   PROTOTYPES ********************************************************/
4178c2ecf20Sopenharmony_ci/*****************************************************************************/
4188c2ecf20Sopenharmony_ci/*** BEGIN Interface Used by the World ***************************************/
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic inline int is_laguna(const struct cirrusfb_info *cinfo)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int opencount;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/*--- Open /dev/fbx ---------------------------------------------------------*/
4288c2ecf20Sopenharmony_cistatic int cirrusfb_open(struct fb_info *info, int user)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	if (opencount++ == 0)
4318c2ecf20Sopenharmony_ci		switch_monitor(info->par, 1);
4328c2ecf20Sopenharmony_ci	return 0;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/*--- Close /dev/fbx --------------------------------------------------------*/
4368c2ecf20Sopenharmony_cistatic int cirrusfb_release(struct fb_info *info, int user)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	if (--opencount == 0)
4398c2ecf20Sopenharmony_ci		switch_monitor(info->par, 0);
4408c2ecf20Sopenharmony_ci	return 0;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci/**** END   Interface used by the World *************************************/
4448c2ecf20Sopenharmony_ci/****************************************************************************/
4458c2ecf20Sopenharmony_ci/**** BEGIN Hardware specific Routines **************************************/
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci/* Check if the MCLK is not a better clock source */
4488c2ecf20Sopenharmony_cistatic int cirrusfb_check_mclk(struct fb_info *info, long freq)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
4518c2ecf20Sopenharmony_ci	long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* Read MCLK value */
4548c2ecf20Sopenharmony_ci	mclk = (14318 * mclk) >> 3;
4558c2ecf20Sopenharmony_ci	dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* Determine if we should use MCLK instead of VCLK, and if so, what we
4588c2ecf20Sopenharmony_ci	 * should divide it by to get VCLK
4598c2ecf20Sopenharmony_ci	 */
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (abs(freq - mclk) < 250) {
4628c2ecf20Sopenharmony_ci		dev_dbg(info->device, "Using VCLK = MCLK\n");
4638c2ecf20Sopenharmony_ci		return 1;
4648c2ecf20Sopenharmony_ci	} else if (abs(freq - (mclk / 2)) < 250) {
4658c2ecf20Sopenharmony_ci		dev_dbg(info->device, "Using VCLK = MCLK/2\n");
4668c2ecf20Sopenharmony_ci		return 2;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return 0;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
4738c2ecf20Sopenharmony_ci				   struct fb_info *info)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	long freq;
4768c2ecf20Sopenharmony_ci	long maxclock;
4778c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
4788c2ecf20Sopenharmony_ci	unsigned maxclockidx = var->bits_per_pixel >> 3;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/* convert from ps to kHz */
4818c2ecf20Sopenharmony_ci	freq = PICOS2KHZ(var->pixclock ? : 1);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
4848c2ecf20Sopenharmony_ci	cinfo->multiplexing = 0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* If the frequency is greater than we can support, we might be able
4878c2ecf20Sopenharmony_ci	 * to use multiplexing for the video mode */
4888c2ecf20Sopenharmony_ci	if (freq > maxclock) {
4898c2ecf20Sopenharmony_ci		var->pixclock = KHZ2PICOS(maxclock);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		while ((freq = PICOS2KHZ(var->pixclock)) > maxclock)
4928c2ecf20Sopenharmony_ci			var->pixclock++;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci	dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/*
4978c2ecf20Sopenharmony_ci	 * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
4988c2ecf20Sopenharmony_ci	 * pixel clock
4998c2ecf20Sopenharmony_ci	 */
5008c2ecf20Sopenharmony_ci	if (var->bits_per_pixel == 8) {
5018c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
5028c2ecf20Sopenharmony_ci		case BT_ALPINE:
5038c2ecf20Sopenharmony_ci		case BT_SD64:
5048c2ecf20Sopenharmony_ci		case BT_PICASSO4:
5058c2ecf20Sopenharmony_ci			if (freq > 85500)
5068c2ecf20Sopenharmony_ci				cinfo->multiplexing = 1;
5078c2ecf20Sopenharmony_ci			break;
5088c2ecf20Sopenharmony_ci		case BT_GD5480:
5098c2ecf20Sopenharmony_ci			if (freq > 135100)
5108c2ecf20Sopenharmony_ci				cinfo->multiplexing = 1;
5118c2ecf20Sopenharmony_ci			break;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		default:
5148c2ecf20Sopenharmony_ci			break;
5158c2ecf20Sopenharmony_ci		}
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* If we have a 1MB 5434, we need to put ourselves in a mode where
5198c2ecf20Sopenharmony_ci	 * the VCLK is double the pixel clock. */
5208c2ecf20Sopenharmony_ci	cinfo->doubleVCLK = 0;
5218c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ &&
5228c2ecf20Sopenharmony_ci	    var->bits_per_pixel == 16) {
5238c2ecf20Sopenharmony_ci		cinfo->doubleVCLK = 1;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic int cirrusfb_check_var(struct fb_var_screeninfo *var,
5308c2ecf20Sopenharmony_ci			      struct fb_info *info)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	int yres;
5338c2ecf20Sopenharmony_ci	/* memory size in pixels */
5348c2ecf20Sopenharmony_ci	unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
5358c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	switch (var->bits_per_pixel) {
5388c2ecf20Sopenharmony_ci	case 1:
5398c2ecf20Sopenharmony_ci		var->red.offset = 0;
5408c2ecf20Sopenharmony_ci		var->red.length = 1;
5418c2ecf20Sopenharmony_ci		var->green = var->red;
5428c2ecf20Sopenharmony_ci		var->blue = var->red;
5438c2ecf20Sopenharmony_ci		break;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	case 8:
5468c2ecf20Sopenharmony_ci		var->red.offset = 0;
5478c2ecf20Sopenharmony_ci		var->red.length = 8;
5488c2ecf20Sopenharmony_ci		var->green = var->red;
5498c2ecf20Sopenharmony_ci		var->blue = var->red;
5508c2ecf20Sopenharmony_ci		break;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	case 16:
5538c2ecf20Sopenharmony_ci		var->red.offset = 11;
5548c2ecf20Sopenharmony_ci		var->green.offset = 5;
5558c2ecf20Sopenharmony_ci		var->blue.offset = 0;
5568c2ecf20Sopenharmony_ci		var->red.length = 5;
5578c2ecf20Sopenharmony_ci		var->green.length = 6;
5588c2ecf20Sopenharmony_ci		var->blue.length = 5;
5598c2ecf20Sopenharmony_ci		break;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	case 24:
5628c2ecf20Sopenharmony_ci		var->red.offset = 16;
5638c2ecf20Sopenharmony_ci		var->green.offset = 8;
5648c2ecf20Sopenharmony_ci		var->blue.offset = 0;
5658c2ecf20Sopenharmony_ci		var->red.length = 8;
5668c2ecf20Sopenharmony_ci		var->green.length = 8;
5678c2ecf20Sopenharmony_ci		var->blue.length = 8;
5688c2ecf20Sopenharmony_ci		break;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	default:
5718c2ecf20Sopenharmony_ci		dev_dbg(info->device,
5728c2ecf20Sopenharmony_ci			"Unsupported bpp size: %d\n", var->bits_per_pixel);
5738c2ecf20Sopenharmony_ci		return -EINVAL;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (var->xres_virtual < var->xres)
5778c2ecf20Sopenharmony_ci		var->xres_virtual = var->xres;
5788c2ecf20Sopenharmony_ci	/* use highest possible virtual resolution */
5798c2ecf20Sopenharmony_ci	if (var->yres_virtual == -1) {
5808c2ecf20Sopenharmony_ci		var->yres_virtual = pixels / var->xres_virtual;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci		dev_info(info->device,
5838c2ecf20Sopenharmony_ci			 "virtual resolution set to maximum of %dx%d\n",
5848c2ecf20Sopenharmony_ci			 var->xres_virtual, var->yres_virtual);
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci	if (var->yres_virtual < var->yres)
5878c2ecf20Sopenharmony_ci		var->yres_virtual = var->yres;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (var->xres_virtual * var->yres_virtual > pixels) {
5908c2ecf20Sopenharmony_ci		dev_err(info->device, "mode %dx%dx%d rejected... "
5918c2ecf20Sopenharmony_ci		      "virtual resolution too high to fit into video memory!\n",
5928c2ecf20Sopenharmony_ci			var->xres_virtual, var->yres_virtual,
5938c2ecf20Sopenharmony_ci			var->bits_per_pixel);
5948c2ecf20Sopenharmony_ci		return -EINVAL;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* truncate xoffset and yoffset to maximum if too high */
5988c2ecf20Sopenharmony_ci	if (var->xoffset > var->xres_virtual - var->xres)
5998c2ecf20Sopenharmony_ci		var->xoffset = var->xres_virtual - var->xres - 1;
6008c2ecf20Sopenharmony_ci	if (var->yoffset > var->yres_virtual - var->yres)
6018c2ecf20Sopenharmony_ci		var->yoffset = var->yres_virtual - var->yres - 1;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	var->red.msb_right =
6048c2ecf20Sopenharmony_ci	    var->green.msb_right =
6058c2ecf20Sopenharmony_ci	    var->blue.msb_right =
6068c2ecf20Sopenharmony_ci	    var->transp.offset =
6078c2ecf20Sopenharmony_ci	    var->transp.length =
6088c2ecf20Sopenharmony_ci	    var->transp.msb_right = 0;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	yres = var->yres;
6118c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE)
6128c2ecf20Sopenharmony_ci		yres *= 2;
6138c2ecf20Sopenharmony_ci	else if (var->vmode & FB_VMODE_INTERLACED)
6148c2ecf20Sopenharmony_ci		yres = (yres + 1) / 2;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (yres >= 1280) {
6178c2ecf20Sopenharmony_ci		dev_err(info->device, "ERROR: VerticalTotal >= 1280; "
6188c2ecf20Sopenharmony_ci			"special treatment required! (TODO)\n");
6198c2ecf20Sopenharmony_ci		return -EINVAL;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (cirrusfb_check_pixclock(var, info))
6238c2ecf20Sopenharmony_ci		return -EINVAL;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (!is_laguna(cinfo))
6268c2ecf20Sopenharmony_ci		var->accel_flags = FB_ACCELF_TEXT;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return 0;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
6348c2ecf20Sopenharmony_ci	unsigned char old1f, old1e;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	assert(cinfo != NULL);
6378c2ecf20Sopenharmony_ci	old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (div) {
6408c2ecf20Sopenharmony_ci		dev_dbg(info->device, "Set %s as pixclock source.\n",
6418c2ecf20Sopenharmony_ci			(div == 2) ? "MCLK/2" : "MCLK");
6428c2ecf20Sopenharmony_ci		old1f |= 0x40;
6438c2ecf20Sopenharmony_ci		old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
6448c2ecf20Sopenharmony_ci		if (div == 2)
6458c2ecf20Sopenharmony_ci			old1e |= 1;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci/*************************************************************************
6538c2ecf20Sopenharmony_ci	cirrusfb_set_par_foo()
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	actually writes the values for a new video mode into the hardware,
6568c2ecf20Sopenharmony_ci**************************************************************************/
6578c2ecf20Sopenharmony_cistatic int cirrusfb_set_par_foo(struct fb_info *info)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
6608c2ecf20Sopenharmony_ci	struct fb_var_screeninfo *var = &info->var;
6618c2ecf20Sopenharmony_ci	u8 __iomem *regbase = cinfo->regbase;
6628c2ecf20Sopenharmony_ci	unsigned char tmp;
6638c2ecf20Sopenharmony_ci	int pitch;
6648c2ecf20Sopenharmony_ci	const struct cirrusfb_board_info_rec *bi;
6658c2ecf20Sopenharmony_ci	int hdispend, hsyncstart, hsyncend, htotal;
6668c2ecf20Sopenharmony_ci	int yres, vdispend, vsyncstart, vsyncend, vtotal;
6678c2ecf20Sopenharmony_ci	long freq;
6688c2ecf20Sopenharmony_ci	int nom, den, div;
6698c2ecf20Sopenharmony_ci	unsigned int control = 0, format = 0, threshold = 0;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
6728c2ecf20Sopenharmony_ci	       var->xres, var->yres, var->bits_per_pixel);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	switch (var->bits_per_pixel) {
6758c2ecf20Sopenharmony_ci	case 1:
6768c2ecf20Sopenharmony_ci		info->fix.line_length = var->xres_virtual / 8;
6778c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_MONO10;
6788c2ecf20Sopenharmony_ci		break;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	case 8:
6818c2ecf20Sopenharmony_ci		info->fix.line_length = var->xres_virtual;
6828c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
6838c2ecf20Sopenharmony_ci		break;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	case 16:
6868c2ecf20Sopenharmony_ci	case 24:
6878c2ecf20Sopenharmony_ci		info->fix.line_length = var->xres_virtual *
6888c2ecf20Sopenharmony_ci					var->bits_per_pixel >> 3;
6898c2ecf20Sopenharmony_ci		info->fix.visual = FB_VISUAL_TRUECOLOR;
6908c2ecf20Sopenharmony_ci		break;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	info->fix.type = FB_TYPE_PACKED_PIXELS;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	init_vgachip(info);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	bi = &cirrusfb_board_info[cinfo->btype];
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	hsyncstart = var->xres + var->right_margin;
6998c2ecf20Sopenharmony_ci	hsyncend = hsyncstart + var->hsync_len;
7008c2ecf20Sopenharmony_ci	htotal = (hsyncend + var->left_margin) / 8;
7018c2ecf20Sopenharmony_ci	hdispend = var->xres / 8;
7028c2ecf20Sopenharmony_ci	hsyncstart = hsyncstart / 8;
7038c2ecf20Sopenharmony_ci	hsyncend = hsyncend / 8;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	vdispend = var->yres;
7068c2ecf20Sopenharmony_ci	vsyncstart = vdispend + var->lower_margin;
7078c2ecf20Sopenharmony_ci	vsyncend = vsyncstart + var->vsync_len;
7088c2ecf20Sopenharmony_ci	vtotal = vsyncend + var->upper_margin;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE) {
7118c2ecf20Sopenharmony_ci		vdispend *= 2;
7128c2ecf20Sopenharmony_ci		vsyncstart *= 2;
7138c2ecf20Sopenharmony_ci		vsyncend *= 2;
7148c2ecf20Sopenharmony_ci		vtotal *= 2;
7158c2ecf20Sopenharmony_ci	} else if (var->vmode & FB_VMODE_INTERLACED) {
7168c2ecf20Sopenharmony_ci		vdispend = (vdispend + 1) / 2;
7178c2ecf20Sopenharmony_ci		vsyncstart = (vsyncstart + 1) / 2;
7188c2ecf20Sopenharmony_ci		vsyncend = (vsyncend + 1) / 2;
7198c2ecf20Sopenharmony_ci		vtotal = (vtotal + 1) / 2;
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci	yres = vdispend;
7228c2ecf20Sopenharmony_ci	if (yres >= 1024) {
7238c2ecf20Sopenharmony_ci		vtotal /= 2;
7248c2ecf20Sopenharmony_ci		vsyncstart /= 2;
7258c2ecf20Sopenharmony_ci		vsyncend /= 2;
7268c2ecf20Sopenharmony_ci		vdispend /= 2;
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	vdispend -= 1;
7308c2ecf20Sopenharmony_ci	vsyncstart -= 1;
7318c2ecf20Sopenharmony_ci	vsyncend -= 1;
7328c2ecf20Sopenharmony_ci	vtotal -= 2;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (cinfo->multiplexing) {
7358c2ecf20Sopenharmony_ci		htotal /= 2;
7368c2ecf20Sopenharmony_ci		hsyncstart /= 2;
7378c2ecf20Sopenharmony_ci		hsyncend /= 2;
7388c2ecf20Sopenharmony_ci		hdispend /= 2;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	htotal -= 5;
7428c2ecf20Sopenharmony_ci	hdispend -= 1;
7438c2ecf20Sopenharmony_ci	hsyncstart += 1;
7448c2ecf20Sopenharmony_ci	hsyncend += 1;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
7478c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	/* if debugging is enabled, all parameters get output before writing */
7508c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT0: %d\n", htotal);
7518c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT1: %d\n", hdispend);
7548c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT2: %d\n", var->xres / 8);
7578c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	/*  + 128: Compatible read */
7608c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32);
7618c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
7628c2ecf20Sopenharmony_ci		 128 + ((htotal + 5) % 32));
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT4: %d\n", hsyncstart);
7658c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	tmp = hsyncend % 32;
7688c2ecf20Sopenharmony_ci	if ((htotal + 5) & 32)
7698c2ecf20Sopenharmony_ci		tmp += 128;
7708c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT5: %d\n", tmp);
7718c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff);
7748c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	tmp = 16;		/* LineCompare bit #9 */
7778c2ecf20Sopenharmony_ci	if (vtotal & 256)
7788c2ecf20Sopenharmony_ci		tmp |= 1;
7798c2ecf20Sopenharmony_ci	if (vdispend & 256)
7808c2ecf20Sopenharmony_ci		tmp |= 2;
7818c2ecf20Sopenharmony_ci	if (vsyncstart & 256)
7828c2ecf20Sopenharmony_ci		tmp |= 4;
7838c2ecf20Sopenharmony_ci	if ((vdispend + 1) & 256)
7848c2ecf20Sopenharmony_ci		tmp |= 8;
7858c2ecf20Sopenharmony_ci	if (vtotal & 512)
7868c2ecf20Sopenharmony_ci		tmp |= 32;
7878c2ecf20Sopenharmony_ci	if (vdispend & 512)
7888c2ecf20Sopenharmony_ci		tmp |= 64;
7898c2ecf20Sopenharmony_ci	if (vsyncstart & 512)
7908c2ecf20Sopenharmony_ci		tmp |= 128;
7918c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT7: %d\n", tmp);
7928c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	tmp = 0x40;		/* LineCompare bit #8 */
7958c2ecf20Sopenharmony_ci	if ((vdispend + 1) & 512)
7968c2ecf20Sopenharmony_ci		tmp |= 0x20;
7978c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_DOUBLE)
7988c2ecf20Sopenharmony_ci		tmp |= 0x80;
7998c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT9: %d\n", tmp);
8008c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff);
8038c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16);
8068c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff);
8098c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff);
8128c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff);
8158c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT18: 0xff\n");
8188c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	tmp = 0;
8218c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED)
8228c2ecf20Sopenharmony_ci		tmp |= 1;
8238c2ecf20Sopenharmony_ci	if ((htotal + 5) & 64)
8248c2ecf20Sopenharmony_ci		tmp |= 16;
8258c2ecf20Sopenharmony_ci	if ((htotal + 5) & 128)
8268c2ecf20Sopenharmony_ci		tmp |= 32;
8278c2ecf20Sopenharmony_ci	if (vtotal & 256)
8288c2ecf20Sopenharmony_ci		tmp |= 64;
8298c2ecf20Sopenharmony_ci	if (vtotal & 512)
8308c2ecf20Sopenharmony_ci		tmp |= 128;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CRT1a: %d\n", tmp);
8338c2ecf20Sopenharmony_ci	vga_wcrt(regbase, CL_CRT1A, tmp);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	freq = PICOS2KHZ(var->pixclock);
8368c2ecf20Sopenharmony_ci	if (var->bits_per_pixel == 24)
8378c2ecf20Sopenharmony_ci		if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
8388c2ecf20Sopenharmony_ci			freq *= 3;
8398c2ecf20Sopenharmony_ci	if (cinfo->multiplexing)
8408c2ecf20Sopenharmony_ci		freq /= 2;
8418c2ecf20Sopenharmony_ci	if (cinfo->doubleVCLK)
8428c2ecf20Sopenharmony_ci		freq *= 2;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	bestclock(freq, &nom, &den, &div);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	dev_dbg(info->device, "VCLK freq: %ld kHz  nom: %d  den: %d  div: %d\n",
8478c2ecf20Sopenharmony_ci		freq, nom, den, div);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/* set VCLK0 */
8508c2ecf20Sopenharmony_ci	/* hardware RefClock: 14.31818 MHz */
8518c2ecf20Sopenharmony_ci	/* formula: VClk = (OSC * N) / (D * (1+P)) */
8528c2ecf20Sopenharmony_ci	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 ||
8558c2ecf20Sopenharmony_ci	    cinfo->btype == BT_SD64) {
8568c2ecf20Sopenharmony_ci		/* if freq is close to mclk or mclk/2 select mclk
8578c2ecf20Sopenharmony_ci		 * as clock source
8588c2ecf20Sopenharmony_ci		 */
8598c2ecf20Sopenharmony_ci		int divMCLK = cirrusfb_check_mclk(info, freq);
8608c2ecf20Sopenharmony_ci		if (divMCLK)
8618c2ecf20Sopenharmony_ci			nom = 0;
8628c2ecf20Sopenharmony_ci		cirrusfb_set_mclk_as_source(info, divMCLK);
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci	if (is_laguna(cinfo)) {
8658c2ecf20Sopenharmony_ci		long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
8668c2ecf20Sopenharmony_ci		unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
8678c2ecf20Sopenharmony_ci		unsigned short tile_control;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		if (cinfo->btype == BT_LAGUNAB) {
8708c2ecf20Sopenharmony_ci			tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
8718c2ecf20Sopenharmony_ci			tile_control &= ~0x80;
8728c2ecf20Sopenharmony_ci			fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
8768c2ecf20Sopenharmony_ci		fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
8778c2ecf20Sopenharmony_ci		control = fb_readw(cinfo->laguna_mmio + 0x402);
8788c2ecf20Sopenharmony_ci		threshold = fb_readw(cinfo->laguna_mmio + 0xea);
8798c2ecf20Sopenharmony_ci		control &= ~0x6800;
8808c2ecf20Sopenharmony_ci		format = 0;
8818c2ecf20Sopenharmony_ci		threshold &= 0xffc0 & 0x3fbf;
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci	if (nom) {
8848c2ecf20Sopenharmony_ci		tmp = den << 1;
8858c2ecf20Sopenharmony_ci		if (div != 0)
8868c2ecf20Sopenharmony_ci			tmp |= 1;
8878c2ecf20Sopenharmony_ci		/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
8888c2ecf20Sopenharmony_ci		if ((cinfo->btype == BT_SD64) ||
8898c2ecf20Sopenharmony_ci		    (cinfo->btype == BT_ALPINE) ||
8908c2ecf20Sopenharmony_ci		    (cinfo->btype == BT_GD5480))
8918c2ecf20Sopenharmony_ci			tmp |= 0x80;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		/* Laguna chipset has reversed clock registers */
8948c2ecf20Sopenharmony_ci		if (is_laguna(cinfo)) {
8958c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRE, tmp);
8968c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR1E, nom);
8978c2ecf20Sopenharmony_ci		} else {
8988c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRE, nom);
8998c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR1E, tmp);
9008c2ecf20Sopenharmony_ci		}
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (yres >= 1024)
9048c2ecf20Sopenharmony_ci		/* 1280x1024 */
9058c2ecf20Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
9068c2ecf20Sopenharmony_ci	else
9078c2ecf20Sopenharmony_ci		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
9088c2ecf20Sopenharmony_ci		 * address wrap, no compat. */
9098c2ecf20Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	/* don't know if it would hurt to also program this if no interlaced */
9128c2ecf20Sopenharmony_ci	/* mode is used, but I feel better this way.. :-) */
9138c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_INTERLACED)
9148c2ecf20Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);
9158c2ecf20Sopenharmony_ci	else
9168c2ecf20Sopenharmony_ci		vga_wcrt(regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	/* adjust horizontal/vertical sync type (low/high), use VCLK3 */
9198c2ecf20Sopenharmony_ci	/* enable display memory & CRTC I/O address for color mode */
9208c2ecf20Sopenharmony_ci	tmp = 0x03 | 0xc;
9218c2ecf20Sopenharmony_ci	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
9228c2ecf20Sopenharmony_ci		tmp |= 0x40;
9238c2ecf20Sopenharmony_ci	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
9248c2ecf20Sopenharmony_ci		tmp |= 0x80;
9258c2ecf20Sopenharmony_ci	WGen(cinfo, VGA_MIS_W, tmp);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* text cursor on and start line */
9288c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
9298c2ecf20Sopenharmony_ci	/* text cursor end line */
9308c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/******************************************************
9338c2ecf20Sopenharmony_ci	 *
9348c2ecf20Sopenharmony_ci	 * 1 bpp
9358c2ecf20Sopenharmony_ci	 *
9368c2ecf20Sopenharmony_ci	 */
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	/* programming for different color depths */
9398c2ecf20Sopenharmony_ci	if (var->bits_per_pixel == 1) {
9408c2ecf20Sopenharmony_ci		dev_dbg(info->device, "preparing for 1 bit deep display\n");
9418c2ecf20Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 0);	/* mode register */
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		/* SR07 */
9448c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
9458c2ecf20Sopenharmony_ci		case BT_SD64:
9468c2ecf20Sopenharmony_ci		case BT_PICCOLO:
9478c2ecf20Sopenharmony_ci		case BT_PICASSO:
9488c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
9498c2ecf20Sopenharmony_ci		case BT_PICASSO4:
9508c2ecf20Sopenharmony_ci		case BT_ALPINE:
9518c2ecf20Sopenharmony_ci		case BT_GD5480:
9528c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
9538c2ecf20Sopenharmony_ci				 cinfo->multiplexing ?
9548c2ecf20Sopenharmony_ci					bi->sr07_1bpp_mux : bi->sr07_1bpp);
9558c2ecf20Sopenharmony_ci			break;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci		case BT_LAGUNA:
9588c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
9598c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
9608c2ecf20Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) & ~0x01);
9618c2ecf20Sopenharmony_ci			break;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci		default:
9648c2ecf20Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
9658c2ecf20Sopenharmony_ci			break;
9668c2ecf20Sopenharmony_ci		}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci		/* Extended Sequencer Mode */
9698c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		case BT_PICCOLO:
9728c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
9738c2ecf20Sopenharmony_ci			/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
9748c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
9758c2ecf20Sopenharmony_ci			break;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci		case BT_PICASSO:
9788c2ecf20Sopenharmony_ci			/* ## vorher d0 avoid FIFO underruns..? */
9798c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xd0);
9808c2ecf20Sopenharmony_ci			break;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci		case BT_SD64:
9838c2ecf20Sopenharmony_ci		case BT_PICASSO4:
9848c2ecf20Sopenharmony_ci		case BT_ALPINE:
9858c2ecf20Sopenharmony_ci		case BT_GD5480:
9868c2ecf20Sopenharmony_ci		case BT_LAGUNA:
9878c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
9888c2ecf20Sopenharmony_ci			/* do nothing */
9898c2ecf20Sopenharmony_ci			break;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci		default:
9928c2ecf20Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
9938c2ecf20Sopenharmony_ci			break;
9948c2ecf20Sopenharmony_ci		}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci		/* pixel mask: pass-through for first plane */
9978c2ecf20Sopenharmony_ci		WGen(cinfo, VGA_PEL_MSK, 0x01);
9988c2ecf20Sopenharmony_ci		if (cinfo->multiplexing)
9998c2ecf20Sopenharmony_ci			/* hidden dac reg: 1280x1024 */
10008c2ecf20Sopenharmony_ci			WHDR(cinfo, 0x4a);
10018c2ecf20Sopenharmony_ci		else
10028c2ecf20Sopenharmony_ci			/* hidden dac: nothing */
10038c2ecf20Sopenharmony_ci			WHDR(cinfo, 0);
10048c2ecf20Sopenharmony_ci		/* memory mode: odd/even, ext. memory */
10058c2ecf20Sopenharmony_ci		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
10068c2ecf20Sopenharmony_ci		/* plane mask: only write to first plane */
10078c2ecf20Sopenharmony_ci		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	/******************************************************
10118c2ecf20Sopenharmony_ci	 *
10128c2ecf20Sopenharmony_ci	 * 8 bpp
10138c2ecf20Sopenharmony_ci	 *
10148c2ecf20Sopenharmony_ci	 */
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	else if (var->bits_per_pixel == 8) {
10178c2ecf20Sopenharmony_ci		dev_dbg(info->device, "preparing for 8 bit deep display\n");
10188c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
10198c2ecf20Sopenharmony_ci		case BT_SD64:
10208c2ecf20Sopenharmony_ci		case BT_PICCOLO:
10218c2ecf20Sopenharmony_ci		case BT_PICASSO:
10228c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
10238c2ecf20Sopenharmony_ci		case BT_PICASSO4:
10248c2ecf20Sopenharmony_ci		case BT_ALPINE:
10258c2ecf20Sopenharmony_ci		case BT_GD5480:
10268c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
10278c2ecf20Sopenharmony_ci				  cinfo->multiplexing ?
10288c2ecf20Sopenharmony_ci					bi->sr07_8bpp_mux : bi->sr07_8bpp);
10298c2ecf20Sopenharmony_ci			break;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci		case BT_LAGUNA:
10328c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
10338c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
10348c2ecf20Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) | 0x01);
10358c2ecf20Sopenharmony_ci			threshold |= 0x10;
10368c2ecf20Sopenharmony_ci			break;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci		default:
10398c2ecf20Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
10408c2ecf20Sopenharmony_ci			break;
10418c2ecf20Sopenharmony_ci		}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
10448c2ecf20Sopenharmony_ci		case BT_PICCOLO:
10458c2ecf20Sopenharmony_ci		case BT_PICASSO:
10468c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
10478c2ecf20Sopenharmony_ci			/* Fast Page-Mode writes */
10488c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
10498c2ecf20Sopenharmony_ci			break;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		case BT_PICASSO4:
10528c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
10538c2ecf20Sopenharmony_ci			/* ### INCOMPLETE!! */
10548c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb8);
10558c2ecf20Sopenharmony_ci#endif
10568c2ecf20Sopenharmony_ci		case BT_ALPINE:
10578c2ecf20Sopenharmony_ci		case BT_SD64:
10588c2ecf20Sopenharmony_ci		case BT_GD5480:
10598c2ecf20Sopenharmony_ci		case BT_LAGUNA:
10608c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
10618c2ecf20Sopenharmony_ci			/* do nothing */
10628c2ecf20Sopenharmony_ci			break;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		default:
10658c2ecf20Sopenharmony_ci			dev_warn(info->device, "unknown board\n");
10668c2ecf20Sopenharmony_ci			break;
10678c2ecf20Sopenharmony_ci		}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci		/* mode register: 256 color mode */
10708c2ecf20Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 64);
10718c2ecf20Sopenharmony_ci		if (cinfo->multiplexing)
10728c2ecf20Sopenharmony_ci			/* hidden dac reg: 1280x1024 */
10738c2ecf20Sopenharmony_ci			WHDR(cinfo, 0x4a);
10748c2ecf20Sopenharmony_ci		else
10758c2ecf20Sopenharmony_ci			/* hidden dac: nothing */
10768c2ecf20Sopenharmony_ci			WHDR(cinfo, 0);
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	/******************************************************
10808c2ecf20Sopenharmony_ci	 *
10818c2ecf20Sopenharmony_ci	 * 16 bpp
10828c2ecf20Sopenharmony_ci	 *
10838c2ecf20Sopenharmony_ci	 */
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	else if (var->bits_per_pixel == 16) {
10868c2ecf20Sopenharmony_ci		dev_dbg(info->device, "preparing for 16 bit deep display\n");
10878c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
10888c2ecf20Sopenharmony_ci		case BT_PICCOLO:
10898c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
10908c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x87);
10918c2ecf20Sopenharmony_ci			/* Fast Page-Mode writes */
10928c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
10938c2ecf20Sopenharmony_ci			break;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci		case BT_PICASSO:
10968c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x27);
10978c2ecf20Sopenharmony_ci			/* Fast Page-Mode writes */
10988c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
10998c2ecf20Sopenharmony_ci			break;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		case BT_SD64:
11028c2ecf20Sopenharmony_ci		case BT_PICASSO4:
11038c2ecf20Sopenharmony_ci		case BT_ALPINE:
11048c2ecf20Sopenharmony_ci			/* Extended Sequencer Mode: 256c col. mode */
11058c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
11068c2ecf20Sopenharmony_ci					cinfo->doubleVCLK ? 0xa3 : 0xa7);
11078c2ecf20Sopenharmony_ci			break;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci		case BT_GD5480:
11108c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x17);
11118c2ecf20Sopenharmony_ci			/* We already set SRF and SR1F */
11128c2ecf20Sopenharmony_ci			break;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		case BT_LAGUNA:
11158c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
11168c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
11178c2ecf20Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) & ~0x01);
11188c2ecf20Sopenharmony_ci			control |= 0x2000;
11198c2ecf20Sopenharmony_ci			format |= 0x1400;
11208c2ecf20Sopenharmony_ci			threshold |= 0x10;
11218c2ecf20Sopenharmony_ci			break;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci		default:
11248c2ecf20Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
11258c2ecf20Sopenharmony_ci			break;
11268c2ecf20Sopenharmony_ci		}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci		/* mode register: 256 color mode */
11298c2ecf20Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 64);
11308c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
11318c2ecf20Sopenharmony_ci		WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
11328c2ecf20Sopenharmony_ci#elif defined(CONFIG_ZORRO)
11338c2ecf20Sopenharmony_ci		/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
11348c2ecf20Sopenharmony_ci		WHDR(cinfo, 0xa0);	/* hidden dac reg: nothing special */
11358c2ecf20Sopenharmony_ci#endif
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	/******************************************************
11398c2ecf20Sopenharmony_ci	 *
11408c2ecf20Sopenharmony_ci	 * 24 bpp
11418c2ecf20Sopenharmony_ci	 *
11428c2ecf20Sopenharmony_ci	 */
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	else if (var->bits_per_pixel == 24) {
11458c2ecf20Sopenharmony_ci		dev_dbg(info->device, "preparing for 24 bit deep display\n");
11468c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
11478c2ecf20Sopenharmony_ci		case BT_PICCOLO:
11488c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
11498c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x85);
11508c2ecf20Sopenharmony_ci			/* Fast Page-Mode writes */
11518c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
11528c2ecf20Sopenharmony_ci			break;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci		case BT_PICASSO:
11558c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x25);
11568c2ecf20Sopenharmony_ci			/* Fast Page-Mode writes */
11578c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQRF, 0xb0);
11588c2ecf20Sopenharmony_ci			break;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci		case BT_SD64:
11618c2ecf20Sopenharmony_ci		case BT_PICASSO4:
11628c2ecf20Sopenharmony_ci		case BT_ALPINE:
11638c2ecf20Sopenharmony_ci			/* Extended Sequencer Mode: 256c col. mode */
11648c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0xa5);
11658c2ecf20Sopenharmony_ci			break;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci		case BT_GD5480:
11688c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7, 0x15);
11698c2ecf20Sopenharmony_ci			/* We already set SRF and SR1F */
11708c2ecf20Sopenharmony_ci			break;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci		case BT_LAGUNA:
11738c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
11748c2ecf20Sopenharmony_ci			vga_wseq(regbase, CL_SEQR7,
11758c2ecf20Sopenharmony_ci				vga_rseq(regbase, CL_SEQR7) & ~0x01);
11768c2ecf20Sopenharmony_ci			control |= 0x4000;
11778c2ecf20Sopenharmony_ci			format |= 0x2400;
11788c2ecf20Sopenharmony_ci			threshold |= 0x20;
11798c2ecf20Sopenharmony_ci			break;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci		default:
11828c2ecf20Sopenharmony_ci			dev_warn(info->device, "unknown Board\n");
11838c2ecf20Sopenharmony_ci			break;
11848c2ecf20Sopenharmony_ci		}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci		/* mode register: 256 color mode */
11878c2ecf20Sopenharmony_ci		vga_wgfx(regbase, VGA_GFX_MODE, 64);
11888c2ecf20Sopenharmony_ci		/* hidden dac reg: 8-8-8 mode (24 or 32) */
11898c2ecf20Sopenharmony_ci		WHDR(cinfo, 0xc5);
11908c2ecf20Sopenharmony_ci	}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	/******************************************************
11938c2ecf20Sopenharmony_ci	 *
11948c2ecf20Sopenharmony_ci	 * unknown/unsupported bpp
11958c2ecf20Sopenharmony_ci	 *
11968c2ecf20Sopenharmony_ci	 */
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	else
11998c2ecf20Sopenharmony_ci		dev_err(info->device,
12008c2ecf20Sopenharmony_ci			"What's this? requested color depth == %d.\n",
12018c2ecf20Sopenharmony_ci			var->bits_per_pixel);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	pitch = info->fix.line_length >> 3;
12048c2ecf20Sopenharmony_ci	vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
12058c2ecf20Sopenharmony_ci	tmp = 0x22;
12068c2ecf20Sopenharmony_ci	if (pitch & 0x100)
12078c2ecf20Sopenharmony_ci		tmp |= 0x10;	/* offset overflow bit */
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	/* screen start addr #16-18, fastpagemode cycles */
12108c2ecf20Sopenharmony_ci	vga_wcrt(regbase, CL_CRT1B, tmp);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	/* screen start address bit 19 */
12138c2ecf20Sopenharmony_ci	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
12148c2ecf20Sopenharmony_ci		vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (is_laguna(cinfo)) {
12178c2ecf20Sopenharmony_ci		tmp = 0;
12188c2ecf20Sopenharmony_ci		if ((htotal + 5) & 256)
12198c2ecf20Sopenharmony_ci			tmp |= 128;
12208c2ecf20Sopenharmony_ci		if (hdispend & 256)
12218c2ecf20Sopenharmony_ci			tmp |= 64;
12228c2ecf20Sopenharmony_ci		if (hsyncstart & 256)
12238c2ecf20Sopenharmony_ci			tmp |= 48;
12248c2ecf20Sopenharmony_ci		if (vtotal & 1024)
12258c2ecf20Sopenharmony_ci			tmp |= 8;
12268c2ecf20Sopenharmony_ci		if (vdispend & 1024)
12278c2ecf20Sopenharmony_ci			tmp |= 4;
12288c2ecf20Sopenharmony_ci		if (vsyncstart & 1024)
12298c2ecf20Sopenharmony_ci			tmp |= 3;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci		vga_wcrt(regbase, CL_CRT1E, tmp);
12328c2ecf20Sopenharmony_ci		dev_dbg(info->device, "CRT1e: %d\n", tmp);
12338c2ecf20Sopenharmony_ci	}
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	/* pixel panning */
12368c2ecf20Sopenharmony_ci	vga_wattr(regbase, CL_AR33, 0);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	/* [ EGS: SetOffset(); ] */
12398c2ecf20Sopenharmony_ci	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
12408c2ecf20Sopenharmony_ci	AttrOn(cinfo);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (is_laguna(cinfo)) {
12438c2ecf20Sopenharmony_ci		/* no tiles */
12448c2ecf20Sopenharmony_ci		fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
12458c2ecf20Sopenharmony_ci		fb_writew(format, cinfo->laguna_mmio + 0xc0);
12468c2ecf20Sopenharmony_ci		fb_writew(threshold, cinfo->laguna_mmio + 0xea);
12478c2ecf20Sopenharmony_ci	}
12488c2ecf20Sopenharmony_ci	/* finally, turn on everything - turn off "FullBandwidth" bit */
12498c2ecf20Sopenharmony_ci	/* also, set "DotClock%2" bit where requested */
12508c2ecf20Sopenharmony_ci	tmp = 0x01;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
12538c2ecf20Sopenharmony_ci    if (var->vmode & FB_VMODE_CLOCK_HALVE)
12548c2ecf20Sopenharmony_ci	tmp |= 0x08;
12558c2ecf20Sopenharmony_ci*/
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
12588c2ecf20Sopenharmony_ci	dev_dbg(info->device, "CL_SEQR1: %d\n", tmp);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
12618c2ecf20Sopenharmony_ci	cirrusfb_dbg_reg_dump(info, NULL);
12628c2ecf20Sopenharmony_ci#endif
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	return 0;
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci/* for some reason incomprehensible to me, cirrusfb requires that you write
12688c2ecf20Sopenharmony_ci * the registers twice for the settings to take..grr. -dte */
12698c2ecf20Sopenharmony_cistatic int cirrusfb_set_par(struct fb_info *info)
12708c2ecf20Sopenharmony_ci{
12718c2ecf20Sopenharmony_ci	cirrusfb_set_par_foo(info);
12728c2ecf20Sopenharmony_ci	return cirrusfb_set_par_foo(info);
12738c2ecf20Sopenharmony_ci}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_cistatic int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
12768c2ecf20Sopenharmony_ci			      unsigned blue, unsigned transp,
12778c2ecf20Sopenharmony_ci			      struct fb_info *info)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	if (regno > 255)
12828c2ecf20Sopenharmony_ci		return -EINVAL;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
12858c2ecf20Sopenharmony_ci		u32 v;
12868c2ecf20Sopenharmony_ci		red >>= (16 - info->var.red.length);
12878c2ecf20Sopenharmony_ci		green >>= (16 - info->var.green.length);
12888c2ecf20Sopenharmony_ci		blue >>= (16 - info->var.blue.length);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		if (regno >= 16)
12918c2ecf20Sopenharmony_ci			return 1;
12928c2ecf20Sopenharmony_ci		v = (red << info->var.red.offset) |
12938c2ecf20Sopenharmony_ci		    (green << info->var.green.offset) |
12948c2ecf20Sopenharmony_ci		    (blue << info->var.blue.offset);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		cinfo->pseudo_palette[regno] = v;
12978c2ecf20Sopenharmony_ci		return 0;
12988c2ecf20Sopenharmony_ci	}
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 8)
13018c2ecf20Sopenharmony_ci		WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	return 0;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci/*************************************************************************
13088c2ecf20Sopenharmony_ci	cirrusfb_pan_display()
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	performs display panning - provided hardware permits this
13118c2ecf20Sopenharmony_ci**************************************************************************/
13128c2ecf20Sopenharmony_cistatic int cirrusfb_pan_display(struct fb_var_screeninfo *var,
13138c2ecf20Sopenharmony_ci				struct fb_info *info)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	int xoffset;
13168c2ecf20Sopenharmony_ci	unsigned long base;
13178c2ecf20Sopenharmony_ci	unsigned char tmp, xpix;
13188c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	/* no range checks for xoffset and yoffset,   */
13218c2ecf20Sopenharmony_ci	/* as fb_pan_display has already done this */
13228c2ecf20Sopenharmony_ci	if (var->vmode & FB_VMODE_YWRAP)
13238c2ecf20Sopenharmony_ci		return -EINVAL;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	xoffset = var->xoffset * info->var.bits_per_pixel / 8;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	base = var->yoffset * info->fix.line_length + xoffset;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 1) {
13308c2ecf20Sopenharmony_ci		/* base is already correct */
13318c2ecf20Sopenharmony_ci		xpix = (unsigned char) (var->xoffset % 8);
13328c2ecf20Sopenharmony_ci	} else {
13338c2ecf20Sopenharmony_ci		base /= 4;
13348c2ecf20Sopenharmony_ci		xpix = (unsigned char) ((xoffset % 4) * 2);
13358c2ecf20Sopenharmony_ci	}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	if (!is_laguna(cinfo))
13388c2ecf20Sopenharmony_ci		cirrusfb_WaitBLT(cinfo->regbase);
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	/* lower 8 + 8 bits of screen start address */
13418c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff);
13428c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	/* 0xf2 is %11110010, exclude tmp bits */
13458c2ecf20Sopenharmony_ci	tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2;
13468c2ecf20Sopenharmony_ci	/* construct bits 16, 17 and 18 of screen start address */
13478c2ecf20Sopenharmony_ci	if (base & 0x10000)
13488c2ecf20Sopenharmony_ci		tmp |= 0x01;
13498c2ecf20Sopenharmony_ci	if (base & 0x20000)
13508c2ecf20Sopenharmony_ci		tmp |= 0x04;
13518c2ecf20Sopenharmony_ci	if (base & 0x40000)
13528c2ecf20Sopenharmony_ci		tmp |= 0x08;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, CL_CRT1B, tmp);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* construct bit 19 of screen start address */
13578c2ecf20Sopenharmony_ci	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
13588c2ecf20Sopenharmony_ci		tmp = vga_rcrt(cinfo->regbase, CL_CRT1D);
13598c2ecf20Sopenharmony_ci		if (is_laguna(cinfo))
13608c2ecf20Sopenharmony_ci			tmp = (tmp & ~0x18) | ((base >> 16) & 0x18);
13618c2ecf20Sopenharmony_ci		else
13628c2ecf20Sopenharmony_ci			tmp = (tmp & ~0x80) | ((base >> 12) & 0x80);
13638c2ecf20Sopenharmony_ci		vga_wcrt(cinfo->regbase, CL_CRT1D, tmp);
13648c2ecf20Sopenharmony_ci	}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	/* write pixel panning value to AR33; this does not quite work in 8bpp
13678c2ecf20Sopenharmony_ci	 *
13688c2ecf20Sopenharmony_ci	 * ### Piccolo..? Will this work?
13698c2ecf20Sopenharmony_ci	 */
13708c2ecf20Sopenharmony_ci	if (info->var.bits_per_pixel == 1)
13718c2ecf20Sopenharmony_ci		vga_wattr(cinfo->regbase, CL_AR33, xpix);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	return 0;
13748c2ecf20Sopenharmony_ci}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_cistatic int cirrusfb_blank(int blank_mode, struct fb_info *info)
13778c2ecf20Sopenharmony_ci{
13788c2ecf20Sopenharmony_ci	/*
13798c2ecf20Sopenharmony_ci	 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
13808c2ecf20Sopenharmony_ci	 * then the caller blanks by setting the CLUT (Color Look Up Table)
13818c2ecf20Sopenharmony_ci	 * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
13828c2ecf20Sopenharmony_ci	 * failed due to e.g. a video mode which doesn't support it.
13838c2ecf20Sopenharmony_ci	 * Implements VESA suspend and powerdown modes on hardware that
13848c2ecf20Sopenharmony_ci	 * supports disabling hsync/vsync:
13858c2ecf20Sopenharmony_ci	 *   blank_mode == 2: suspend vsync
13868c2ecf20Sopenharmony_ci	 *   blank_mode == 3: suspend hsync
13878c2ecf20Sopenharmony_ci	 *   blank_mode == 4: powerdown
13888c2ecf20Sopenharmony_ci	 */
13898c2ecf20Sopenharmony_ci	unsigned char val;
13908c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
13918c2ecf20Sopenharmony_ci	int current_mode = cinfo->blank_mode;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING ||
13968c2ecf20Sopenharmony_ci	    current_mode == blank_mode) {
13978c2ecf20Sopenharmony_ci		dev_dbg(info->device, "EXIT, returning 0\n");
13988c2ecf20Sopenharmony_ci		return 0;
13998c2ecf20Sopenharmony_ci	}
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	/* Undo current */
14028c2ecf20Sopenharmony_ci	if (current_mode == FB_BLANK_NORMAL ||
14038c2ecf20Sopenharmony_ci	    current_mode == FB_BLANK_UNBLANK)
14048c2ecf20Sopenharmony_ci		/* clear "FullBandwidth" bit */
14058c2ecf20Sopenharmony_ci		val = 0;
14068c2ecf20Sopenharmony_ci	else
14078c2ecf20Sopenharmony_ci		/* set "FullBandwidth" bit */
14088c2ecf20Sopenharmony_ci		val = 0x20;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf;
14118c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	switch (blank_mode) {
14148c2ecf20Sopenharmony_ci	case FB_BLANK_UNBLANK:
14158c2ecf20Sopenharmony_ci	case FB_BLANK_NORMAL:
14168c2ecf20Sopenharmony_ci		val = 0x00;
14178c2ecf20Sopenharmony_ci		break;
14188c2ecf20Sopenharmony_ci	case FB_BLANK_VSYNC_SUSPEND:
14198c2ecf20Sopenharmony_ci		val = 0x04;
14208c2ecf20Sopenharmony_ci		break;
14218c2ecf20Sopenharmony_ci	case FB_BLANK_HSYNC_SUSPEND:
14228c2ecf20Sopenharmony_ci		val = 0x02;
14238c2ecf20Sopenharmony_ci		break;
14248c2ecf20Sopenharmony_ci	case FB_BLANK_POWERDOWN:
14258c2ecf20Sopenharmony_ci		val = 0x06;
14268c2ecf20Sopenharmony_ci		break;
14278c2ecf20Sopenharmony_ci	default:
14288c2ecf20Sopenharmony_ci		dev_dbg(info->device, "EXIT, returning 1\n");
14298c2ecf20Sopenharmony_ci		return 1;
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRE, val);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	cinfo->blank_mode = blank_mode;
14358c2ecf20Sopenharmony_ci	dev_dbg(info->device, "EXIT, returning 0\n");
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	/* Let fbcon do a soft blank for us */
14388c2ecf20Sopenharmony_ci	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
14398c2ecf20Sopenharmony_ci}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci/**** END   Hardware specific Routines **************************************/
14428c2ecf20Sopenharmony_ci/****************************************************************************/
14438c2ecf20Sopenharmony_ci/**** BEGIN Internal Routines ***********************************************/
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_cistatic void init_vgachip(struct fb_info *info)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
14488c2ecf20Sopenharmony_ci	const struct cirrusfb_board_info_rec *bi;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	assert(cinfo != NULL);
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	bi = &cirrusfb_board_info[cinfo->btype];
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	/* reset board globally */
14558c2ecf20Sopenharmony_ci	switch (cinfo->btype) {
14568c2ecf20Sopenharmony_ci	case BT_PICCOLO:
14578c2ecf20Sopenharmony_ci		WSFR(cinfo, 0x01);
14588c2ecf20Sopenharmony_ci		udelay(500);
14598c2ecf20Sopenharmony_ci		WSFR(cinfo, 0x51);
14608c2ecf20Sopenharmony_ci		udelay(500);
14618c2ecf20Sopenharmony_ci		break;
14628c2ecf20Sopenharmony_ci	case BT_PICASSO:
14638c2ecf20Sopenharmony_ci		WSFR2(cinfo, 0xff);
14648c2ecf20Sopenharmony_ci		udelay(500);
14658c2ecf20Sopenharmony_ci		break;
14668c2ecf20Sopenharmony_ci	case BT_SD64:
14678c2ecf20Sopenharmony_ci	case BT_SPECTRUM:
14688c2ecf20Sopenharmony_ci		WSFR(cinfo, 0x1f);
14698c2ecf20Sopenharmony_ci		udelay(500);
14708c2ecf20Sopenharmony_ci		WSFR(cinfo, 0x4f);
14718c2ecf20Sopenharmony_ci		udelay(500);
14728c2ecf20Sopenharmony_ci		break;
14738c2ecf20Sopenharmony_ci	case BT_PICASSO4:
14748c2ecf20Sopenharmony_ci		/* disable flickerfixer */
14758c2ecf20Sopenharmony_ci		vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
14768c2ecf20Sopenharmony_ci		mdelay(100);
14778c2ecf20Sopenharmony_ci		/* mode */
14788c2ecf20Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
14798c2ecf20Sopenharmony_ci		fallthrough;
14808c2ecf20Sopenharmony_ci	case BT_GD5480:
14818c2ecf20Sopenharmony_ci		/* from Klaus' NetBSD driver: */
14828c2ecf20Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
14838c2ecf20Sopenharmony_ci		fallthrough;
14848c2ecf20Sopenharmony_ci	case BT_ALPINE:
14858c2ecf20Sopenharmony_ci		/* put blitter into 542x compat */
14868c2ecf20Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
14878c2ecf20Sopenharmony_ci		break;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	case BT_LAGUNA:
14908c2ecf20Sopenharmony_ci	case BT_LAGUNAB:
14918c2ecf20Sopenharmony_ci		/* Nothing to do to reset the board. */
14928c2ecf20Sopenharmony_ci		break;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	default:
14958c2ecf20Sopenharmony_ci		dev_err(info->device, "Warning: Unknown board type\n");
14968c2ecf20Sopenharmony_ci		break;
14978c2ecf20Sopenharmony_ci	}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	/* make sure RAM size set by this point */
15008c2ecf20Sopenharmony_ci	assert(info->screen_size > 0);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	/* the P4 is not fully initialized here; I rely on it having been */
15038c2ecf20Sopenharmony_ci	/* inited under AmigaOS already, which seems to work just fine    */
15048c2ecf20Sopenharmony_ci	/* (Klaus advised to do it this way)			      */
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	if (cinfo->btype != BT_PICASSO4) {
15078c2ecf20Sopenharmony_ci		WGen(cinfo, CL_VSSM, 0x10);	/* EGS: 0x16 */
15088c2ecf20Sopenharmony_ci		WGen(cinfo, CL_POS102, 0x01);
15098c2ecf20Sopenharmony_ci		WGen(cinfo, CL_VSSM, 0x08);	/* EGS: 0x0e */
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci		if (cinfo->btype != BT_SD64)
15128c2ecf20Sopenharmony_ci			WGen(cinfo, CL_VSSM2, 0x01);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci		/* reset sequencer logic */
15158c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03);
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci		/* FullBandwidth (video off) and 8/9 dot clock */
15188c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci		/* "magic cookie" - doesn't make any sense to me.. */
15218c2ecf20Sopenharmony_ci/*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
15228c2ecf20Sopenharmony_ci		/* unlock all extension registers */
15238c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
15268c2ecf20Sopenharmony_ci		case BT_GD5480:
15278c2ecf20Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
15288c2ecf20Sopenharmony_ci			break;
15298c2ecf20Sopenharmony_ci		case BT_ALPINE:
15308c2ecf20Sopenharmony_ci		case BT_LAGUNA:
15318c2ecf20Sopenharmony_ci		case BT_LAGUNAB:
15328c2ecf20Sopenharmony_ci			break;
15338c2ecf20Sopenharmony_ci		case BT_SD64:
15348c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
15358c2ecf20Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
15368c2ecf20Sopenharmony_ci#endif
15378c2ecf20Sopenharmony_ci			break;
15388c2ecf20Sopenharmony_ci		default:
15398c2ecf20Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
15408c2ecf20Sopenharmony_ci			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
15418c2ecf20Sopenharmony_ci			break;
15428c2ecf20Sopenharmony_ci		}
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci	/* plane mask: nothing */
15458c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
15468c2ecf20Sopenharmony_ci	/* character map select: doesn't even matter in gx mode */
15478c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
15488c2ecf20Sopenharmony_ci	/* memory mode: chain4, ext. memory */
15498c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	/* controller-internal base address of video memory */
15528c2ecf20Sopenharmony_ci	if (bi->init_sr07)
15538c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	/*  vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
15568c2ecf20Sopenharmony_ci	/* EEPROM control: shouldn't be necessary to write to this at all.. */
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	/* graphics cursor X position (incomplete; position gives rem. 3 bits */
15598c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
15608c2ecf20Sopenharmony_ci	/* graphics cursor Y position (..."... ) */
15618c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
15628c2ecf20Sopenharmony_ci	/* graphics cursor attributes */
15638c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
15648c2ecf20Sopenharmony_ci	/* graphics cursor pattern address */
15658c2ecf20Sopenharmony_ci	vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	/* writing these on a P4 might give problems..  */
15688c2ecf20Sopenharmony_ci	if (cinfo->btype != BT_PICASSO4) {
15698c2ecf20Sopenharmony_ci		/* configuration readback and ext. color */
15708c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
15718c2ecf20Sopenharmony_ci		/* signature generator */
15728c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	/* Screen A preset row scan: none */
15768c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
15778c2ecf20Sopenharmony_ci	/* Text cursor start: disable text cursor */
15788c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
15798c2ecf20Sopenharmony_ci	/* Text cursor end: - */
15808c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
15818c2ecf20Sopenharmony_ci	/* text cursor location high: 0 */
15828c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
15838c2ecf20Sopenharmony_ci	/* text cursor location low: 0 */
15848c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	/* Underline Row scanline: - */
15878c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
15888c2ecf20Sopenharmony_ci	/* ### add 0x40 for text modes with > 30 MHz pixclock */
15898c2ecf20Sopenharmony_ci	/* ext. display controls: ext.adr. wrap */
15908c2ecf20Sopenharmony_ci	vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	/* Set/Reset registers: - */
15938c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
15948c2ecf20Sopenharmony_ci	/* Set/Reset enable: - */
15958c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
15968c2ecf20Sopenharmony_ci	/* Color Compare: - */
15978c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
15988c2ecf20Sopenharmony_ci	/* Data Rotate: - */
15998c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
16008c2ecf20Sopenharmony_ci	/* Read Map Select: - */
16018c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
16028c2ecf20Sopenharmony_ci	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
16038c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
16048c2ecf20Sopenharmony_ci	/* Miscellaneous: memory map base address, graphics mode */
16058c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
16068c2ecf20Sopenharmony_ci	/* Color Don't care: involve all planes */
16078c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
16088c2ecf20Sopenharmony_ci	/* Bit Mask: no mask at all */
16098c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 ||
16128c2ecf20Sopenharmony_ci	    is_laguna(cinfo))
16138c2ecf20Sopenharmony_ci		/* (5434 can't have bit 3 set for bitblt) */
16148c2ecf20Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
16158c2ecf20Sopenharmony_ci	else
16168c2ecf20Sopenharmony_ci	/* Graphics controller mode extensions: finer granularity,
16178c2ecf20Sopenharmony_ci	 * 8byte data latches
16188c2ecf20Sopenharmony_ci	 */
16198c2ecf20Sopenharmony_ci		vga_wgfx(cinfo->regbase, CL_GRB, 0x28);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRC, 0xff);	/* Color Key compare: - */
16228c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRD, 0x00);	/* Color Key compare mask: - */
16238c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GRE, 0x00);	/* Miscellaneous control: - */
16248c2ecf20Sopenharmony_ci	/* Background color byte 1: - */
16258c2ecf20Sopenharmony_ci	/*  vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
16268c2ecf20Sopenharmony_ci	/*  vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	/* Attribute Controller palette registers: "identity mapping" */
16298c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
16308c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
16318c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
16328c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
16338c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
16348c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
16358c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
16368c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
16378c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
16388c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
16398c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
16408c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
16418c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
16428c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
16438c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
16448c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	/* Attribute Controller mode: graphics mode */
16478c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
16488c2ecf20Sopenharmony_ci	/* Overscan color reg.: reg. 0 */
16498c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
16508c2ecf20Sopenharmony_ci	/* Color Plane enable: Enable all 4 planes */
16518c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
16528c2ecf20Sopenharmony_ci	/* Color Select: - */
16538c2ecf20Sopenharmony_ci	vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	WGen(cinfo, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	/* BLT Start/status: Blitter reset */
16588c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
16598c2ecf20Sopenharmony_ci	/* - " -	   : "end-of-reset" */
16608c2ecf20Sopenharmony_ci	vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	/* misc... */
16638c2ecf20Sopenharmony_ci	WHDR(cinfo, 0);	/* Hidden DAC register: - */
16648c2ecf20Sopenharmony_ci	return;
16658c2ecf20Sopenharmony_ci}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_cistatic void switch_monitor(struct cirrusfb_info *cinfo, int on)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO /* only works on Zorro boards */
16708c2ecf20Sopenharmony_ci	static int IsOn = 0;	/* XXX not ok for multiple boards */
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO4)
16738c2ecf20Sopenharmony_ci		return;		/* nothing to switch */
16748c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_ALPINE)
16758c2ecf20Sopenharmony_ci		return;		/* nothing to switch */
16768c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_GD5480)
16778c2ecf20Sopenharmony_ci		return;		/* nothing to switch */
16788c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
16798c2ecf20Sopenharmony_ci		if ((on && !IsOn) || (!on && IsOn))
16808c2ecf20Sopenharmony_ci			WSFR(cinfo, 0xff);
16818c2ecf20Sopenharmony_ci		return;
16828c2ecf20Sopenharmony_ci	}
16838c2ecf20Sopenharmony_ci	if (on) {
16848c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
16858c2ecf20Sopenharmony_ci		case BT_SD64:
16868c2ecf20Sopenharmony_ci			WSFR(cinfo, cinfo->SFR | 0x21);
16878c2ecf20Sopenharmony_ci			break;
16888c2ecf20Sopenharmony_ci		case BT_PICCOLO:
16898c2ecf20Sopenharmony_ci			WSFR(cinfo, cinfo->SFR | 0x28);
16908c2ecf20Sopenharmony_ci			break;
16918c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
16928c2ecf20Sopenharmony_ci			WSFR(cinfo, 0x6f);
16938c2ecf20Sopenharmony_ci			break;
16948c2ecf20Sopenharmony_ci		default: /* do nothing */ break;
16958c2ecf20Sopenharmony_ci		}
16968c2ecf20Sopenharmony_ci	} else {
16978c2ecf20Sopenharmony_ci		switch (cinfo->btype) {
16988c2ecf20Sopenharmony_ci		case BT_SD64:
16998c2ecf20Sopenharmony_ci			WSFR(cinfo, cinfo->SFR & 0xde);
17008c2ecf20Sopenharmony_ci			break;
17018c2ecf20Sopenharmony_ci		case BT_PICCOLO:
17028c2ecf20Sopenharmony_ci			WSFR(cinfo, cinfo->SFR & 0xd7);
17038c2ecf20Sopenharmony_ci			break;
17048c2ecf20Sopenharmony_ci		case BT_SPECTRUM:
17058c2ecf20Sopenharmony_ci			WSFR(cinfo, 0x4f);
17068c2ecf20Sopenharmony_ci			break;
17078c2ecf20Sopenharmony_ci		default: /* do nothing */
17088c2ecf20Sopenharmony_ci			break;
17098c2ecf20Sopenharmony_ci		}
17108c2ecf20Sopenharmony_ci	}
17118c2ecf20Sopenharmony_ci#endif /* CONFIG_ZORRO */
17128c2ecf20Sopenharmony_ci}
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci/******************************************/
17158c2ecf20Sopenharmony_ci/* Linux 2.6-style  accelerated functions */
17168c2ecf20Sopenharmony_ci/******************************************/
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_cistatic int cirrusfb_sync(struct fb_info *info)
17198c2ecf20Sopenharmony_ci{
17208c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	if (!is_laguna(cinfo)) {
17238c2ecf20Sopenharmony_ci		while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03)
17248c2ecf20Sopenharmony_ci			cpu_relax();
17258c2ecf20Sopenharmony_ci	}
17268c2ecf20Sopenharmony_ci	return 0;
17278c2ecf20Sopenharmony_ci}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_cistatic void cirrusfb_fillrect(struct fb_info *info,
17308c2ecf20Sopenharmony_ci			      const struct fb_fillrect *region)
17318c2ecf20Sopenharmony_ci{
17328c2ecf20Sopenharmony_ci	struct fb_fillrect modded;
17338c2ecf20Sopenharmony_ci	int vxres, vyres;
17348c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
17358c2ecf20Sopenharmony_ci	int m = info->var.bits_per_pixel;
17368c2ecf20Sopenharmony_ci	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
17378c2ecf20Sopenharmony_ci		cinfo->pseudo_palette[region->color] : region->color;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
17408c2ecf20Sopenharmony_ci		return;
17418c2ecf20Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED) {
17428c2ecf20Sopenharmony_ci		cfb_fillrect(info, region);
17438c2ecf20Sopenharmony_ci		return;
17448c2ecf20Sopenharmony_ci	}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	vxres = info->var.xres_virtual;
17478c2ecf20Sopenharmony_ci	vyres = info->var.yres_virtual;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	memcpy(&modded, region, sizeof(struct fb_fillrect));
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	if (!modded.width || !modded.height ||
17528c2ecf20Sopenharmony_ci	   modded.dx >= vxres || modded.dy >= vyres)
17538c2ecf20Sopenharmony_ci		return;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	if (modded.dx + modded.width  > vxres)
17568c2ecf20Sopenharmony_ci		modded.width  = vxres - modded.dx;
17578c2ecf20Sopenharmony_ci	if (modded.dy + modded.height > vyres)
17588c2ecf20Sopenharmony_ci		modded.height = vyres - modded.dy;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	cirrusfb_RectFill(cinfo->regbase,
17618c2ecf20Sopenharmony_ci			  info->var.bits_per_pixel,
17628c2ecf20Sopenharmony_ci			  (region->dx * m) / 8, region->dy,
17638c2ecf20Sopenharmony_ci			  (region->width * m) / 8, region->height,
17648c2ecf20Sopenharmony_ci			  color, color,
17658c2ecf20Sopenharmony_ci			  info->fix.line_length, 0x40);
17668c2ecf20Sopenharmony_ci}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_cistatic void cirrusfb_copyarea(struct fb_info *info,
17698c2ecf20Sopenharmony_ci			      const struct fb_copyarea *area)
17708c2ecf20Sopenharmony_ci{
17718c2ecf20Sopenharmony_ci	struct fb_copyarea modded;
17728c2ecf20Sopenharmony_ci	u32 vxres, vyres;
17738c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
17748c2ecf20Sopenharmony_ci	int m = info->var.bits_per_pixel;
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
17778c2ecf20Sopenharmony_ci		return;
17788c2ecf20Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED) {
17798c2ecf20Sopenharmony_ci		cfb_copyarea(info, area);
17808c2ecf20Sopenharmony_ci		return;
17818c2ecf20Sopenharmony_ci	}
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	vxres = info->var.xres_virtual;
17848c2ecf20Sopenharmony_ci	vyres = info->var.yres_virtual;
17858c2ecf20Sopenharmony_ci	memcpy(&modded, area, sizeof(struct fb_copyarea));
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (!modded.width || !modded.height ||
17888c2ecf20Sopenharmony_ci	   modded.sx >= vxres || modded.sy >= vyres ||
17898c2ecf20Sopenharmony_ci	   modded.dx >= vxres || modded.dy >= vyres)
17908c2ecf20Sopenharmony_ci		return;
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	if (modded.sx + modded.width > vxres)
17938c2ecf20Sopenharmony_ci		modded.width = vxres - modded.sx;
17948c2ecf20Sopenharmony_ci	if (modded.dx + modded.width > vxres)
17958c2ecf20Sopenharmony_ci		modded.width = vxres - modded.dx;
17968c2ecf20Sopenharmony_ci	if (modded.sy + modded.height > vyres)
17978c2ecf20Sopenharmony_ci		modded.height = vyres - modded.sy;
17988c2ecf20Sopenharmony_ci	if (modded.dy + modded.height > vyres)
17998c2ecf20Sopenharmony_ci		modded.height = vyres - modded.dy;
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
18028c2ecf20Sopenharmony_ci			(area->sx * m) / 8, area->sy,
18038c2ecf20Sopenharmony_ci			(area->dx * m) / 8, area->dy,
18048c2ecf20Sopenharmony_ci			(area->width * m) / 8, area->height,
18058c2ecf20Sopenharmony_ci			info->fix.line_length);
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_cistatic void cirrusfb_imageblit(struct fb_info *info,
18108c2ecf20Sopenharmony_ci			       const struct fb_image *image)
18118c2ecf20Sopenharmony_ci{
18128c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
18138c2ecf20Sopenharmony_ci	unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci	if (info->state != FBINFO_STATE_RUNNING)
18168c2ecf20Sopenharmony_ci		return;
18178c2ecf20Sopenharmony_ci	/* Alpine/SD64 does not work at 24bpp ??? */
18188c2ecf20Sopenharmony_ci	if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
18198c2ecf20Sopenharmony_ci		cfb_imageblit(info, image);
18208c2ecf20Sopenharmony_ci	else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) &&
18218c2ecf20Sopenharmony_ci		  op == 0xc)
18228c2ecf20Sopenharmony_ci		cfb_imageblit(info, image);
18238c2ecf20Sopenharmony_ci	else {
18248c2ecf20Sopenharmony_ci		unsigned size = ((image->width + 7) >> 3) * image->height;
18258c2ecf20Sopenharmony_ci		int m = info->var.bits_per_pixel;
18268c2ecf20Sopenharmony_ci		u32 fg, bg;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci		if (info->var.bits_per_pixel == 8) {
18298c2ecf20Sopenharmony_ci			fg = image->fg_color;
18308c2ecf20Sopenharmony_ci			bg = image->bg_color;
18318c2ecf20Sopenharmony_ci		} else {
18328c2ecf20Sopenharmony_ci			fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
18338c2ecf20Sopenharmony_ci			bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
18348c2ecf20Sopenharmony_ci		}
18358c2ecf20Sopenharmony_ci		if (info->var.bits_per_pixel == 24) {
18368c2ecf20Sopenharmony_ci			/* clear background first */
18378c2ecf20Sopenharmony_ci			cirrusfb_RectFill(cinfo->regbase,
18388c2ecf20Sopenharmony_ci					  info->var.bits_per_pixel,
18398c2ecf20Sopenharmony_ci					  (image->dx * m) / 8, image->dy,
18408c2ecf20Sopenharmony_ci					  (image->width * m) / 8,
18418c2ecf20Sopenharmony_ci					  image->height,
18428c2ecf20Sopenharmony_ci					  bg, bg,
18438c2ecf20Sopenharmony_ci					  info->fix.line_length, 0x40);
18448c2ecf20Sopenharmony_ci		}
18458c2ecf20Sopenharmony_ci		cirrusfb_RectFill(cinfo->regbase,
18468c2ecf20Sopenharmony_ci				  info->var.bits_per_pixel,
18478c2ecf20Sopenharmony_ci				  (image->dx * m) / 8, image->dy,
18488c2ecf20Sopenharmony_ci				  (image->width * m) / 8, image->height,
18498c2ecf20Sopenharmony_ci				  fg, bg,
18508c2ecf20Sopenharmony_ci				  info->fix.line_length, op);
18518c2ecf20Sopenharmony_ci		memcpy(info->screen_base, image->data, size);
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
18568c2ecf20Sopenharmony_cistatic int release_io_ports;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
18598c2ecf20Sopenharmony_ci * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
18608c2ecf20Sopenharmony_ci * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
18618c2ecf20Sopenharmony_ci * seem to have. */
18628c2ecf20Sopenharmony_cistatic unsigned int cirrusfb_get_memsize(struct fb_info *info,
18638c2ecf20Sopenharmony_ci					 u8 __iomem *regbase)
18648c2ecf20Sopenharmony_ci{
18658c2ecf20Sopenharmony_ci	unsigned long mem;
18668c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	if (is_laguna(cinfo)) {
18698c2ecf20Sopenharmony_ci		unsigned char SR14 = vga_rseq(regbase, CL_SEQR14);
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci		mem = ((SR14 & 7) + 1) << 20;
18728c2ecf20Sopenharmony_ci	} else {
18738c2ecf20Sopenharmony_ci		unsigned char SRF = vga_rseq(regbase, CL_SEQRF);
18748c2ecf20Sopenharmony_ci		switch ((SRF & 0x18)) {
18758c2ecf20Sopenharmony_ci		case 0x08:
18768c2ecf20Sopenharmony_ci			mem = 512 * 1024;
18778c2ecf20Sopenharmony_ci			break;
18788c2ecf20Sopenharmony_ci		case 0x10:
18798c2ecf20Sopenharmony_ci			mem = 1024 * 1024;
18808c2ecf20Sopenharmony_ci			break;
18818c2ecf20Sopenharmony_ci		/* 64-bit DRAM data bus width; assume 2MB.
18828c2ecf20Sopenharmony_ci		 * Also indicates 2MB memory on the 5430.
18838c2ecf20Sopenharmony_ci		 */
18848c2ecf20Sopenharmony_ci		case 0x18:
18858c2ecf20Sopenharmony_ci			mem = 2048 * 1024;
18868c2ecf20Sopenharmony_ci			break;
18878c2ecf20Sopenharmony_ci		default:
18888c2ecf20Sopenharmony_ci			dev_warn(info->device, "Unknown memory size!\n");
18898c2ecf20Sopenharmony_ci			mem = 1024 * 1024;
18908c2ecf20Sopenharmony_ci		}
18918c2ecf20Sopenharmony_ci		/* If DRAM bank switching is enabled, there must be
18928c2ecf20Sopenharmony_ci		 * twice as much memory installed. (4MB on the 5434)
18938c2ecf20Sopenharmony_ci		 */
18948c2ecf20Sopenharmony_ci		if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0)
18958c2ecf20Sopenharmony_ci			mem *= 2;
18968c2ecf20Sopenharmony_ci	}
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
18998c2ecf20Sopenharmony_ci	return mem;
19008c2ecf20Sopenharmony_ci}
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_cistatic void get_pci_addrs(const struct pci_dev *pdev,
19038c2ecf20Sopenharmony_ci			  unsigned long *display, unsigned long *registers)
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	assert(pdev != NULL);
19068c2ecf20Sopenharmony_ci	assert(display != NULL);
19078c2ecf20Sopenharmony_ci	assert(registers != NULL);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	*display = 0;
19108c2ecf20Sopenharmony_ci	*registers = 0;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	/* This is a best-guess for now */
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
19158c2ecf20Sopenharmony_ci		*display = pci_resource_start(pdev, 1);
19168c2ecf20Sopenharmony_ci		*registers = pci_resource_start(pdev, 0);
19178c2ecf20Sopenharmony_ci	} else {
19188c2ecf20Sopenharmony_ci		*display = pci_resource_start(pdev, 0);
19198c2ecf20Sopenharmony_ci		*registers = pci_resource_start(pdev, 1);
19208c2ecf20Sopenharmony_ci	}
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	assert(*display != 0);
19238c2ecf20Sopenharmony_ci}
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_cistatic void cirrusfb_pci_unmap(struct fb_info *info)
19268c2ecf20Sopenharmony_ci{
19278c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(info->device);
19288c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	if (cinfo->laguna_mmio == NULL)
19318c2ecf20Sopenharmony_ci		iounmap(cinfo->laguna_mmio);
19328c2ecf20Sopenharmony_ci	iounmap(info->screen_base);
19338c2ecf20Sopenharmony_ci#if 0 /* if system didn't claim this region, we would... */
19348c2ecf20Sopenharmony_ci	release_mem_region(0xA0000, 65535);
19358c2ecf20Sopenharmony_ci#endif
19368c2ecf20Sopenharmony_ci	if (release_io_ports)
19378c2ecf20Sopenharmony_ci		release_region(0x3C0, 32);
19388c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
19398c2ecf20Sopenharmony_ci}
19408c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
19438c2ecf20Sopenharmony_cistatic void cirrusfb_zorro_unmap(struct fb_info *info)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
19468c2ecf20Sopenharmony_ci	struct zorro_dev *zdev = to_zorro_dev(info->device);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (info->fix.smem_start > 16 * MB_)
19498c2ecf20Sopenharmony_ci		iounmap(info->screen_base);
19508c2ecf20Sopenharmony_ci	if (info->fix.mmio_start > 16 * MB_)
19518c2ecf20Sopenharmony_ci		iounmap(cinfo->regbase);
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	zorro_release_device(zdev);
19548c2ecf20Sopenharmony_ci}
19558c2ecf20Sopenharmony_ci#endif /* CONFIG_ZORRO */
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci/* function table of the above functions */
19588c2ecf20Sopenharmony_cistatic const struct fb_ops cirrusfb_ops = {
19598c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
19608c2ecf20Sopenharmony_ci	.fb_open	= cirrusfb_open,
19618c2ecf20Sopenharmony_ci	.fb_release	= cirrusfb_release,
19628c2ecf20Sopenharmony_ci	.fb_setcolreg	= cirrusfb_setcolreg,
19638c2ecf20Sopenharmony_ci	.fb_check_var	= cirrusfb_check_var,
19648c2ecf20Sopenharmony_ci	.fb_set_par	= cirrusfb_set_par,
19658c2ecf20Sopenharmony_ci	.fb_pan_display = cirrusfb_pan_display,
19668c2ecf20Sopenharmony_ci	.fb_blank	= cirrusfb_blank,
19678c2ecf20Sopenharmony_ci	.fb_fillrect	= cirrusfb_fillrect,
19688c2ecf20Sopenharmony_ci	.fb_copyarea	= cirrusfb_copyarea,
19698c2ecf20Sopenharmony_ci	.fb_sync	= cirrusfb_sync,
19708c2ecf20Sopenharmony_ci	.fb_imageblit	= cirrusfb_imageblit,
19718c2ecf20Sopenharmony_ci};
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_cistatic int cirrusfb_set_fbinfo(struct fb_info *info)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
19768c2ecf20Sopenharmony_ci	struct fb_var_screeninfo *var = &info->var;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	info->pseudo_palette = cinfo->pseudo_palette;
19798c2ecf20Sopenharmony_ci	info->flags = FBINFO_DEFAULT
19808c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_XPAN
19818c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_YPAN
19828c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_FILLRECT
19838c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_IMAGEBLIT
19848c2ecf20Sopenharmony_ci		    | FBINFO_HWACCEL_COPYAREA;
19858c2ecf20Sopenharmony_ci	if (noaccel || is_laguna(cinfo)) {
19868c2ecf20Sopenharmony_ci		info->flags |= FBINFO_HWACCEL_DISABLED;
19878c2ecf20Sopenharmony_ci		info->fix.accel = FB_ACCEL_NONE;
19888c2ecf20Sopenharmony_ci	} else
19898c2ecf20Sopenharmony_ci		info->fix.accel = FB_ACCEL_CIRRUS_ALPINE;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	info->fbops = &cirrusfb_ops;
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_GD5480) {
19948c2ecf20Sopenharmony_ci		if (var->bits_per_pixel == 16)
19958c2ecf20Sopenharmony_ci			info->screen_base += 1 * MB_;
19968c2ecf20Sopenharmony_ci		if (var->bits_per_pixel == 32)
19978c2ecf20Sopenharmony_ci			info->screen_base += 2 * MB_;
19988c2ecf20Sopenharmony_ci	}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	/* Fill fix common fields */
20018c2ecf20Sopenharmony_ci	strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
20028c2ecf20Sopenharmony_ci		sizeof(info->fix.id));
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	/* monochrome: only 1 memory plane */
20058c2ecf20Sopenharmony_ci	/* 8 bit and above: Use whole memory area */
20068c2ecf20Sopenharmony_ci	info->fix.smem_len   = info->screen_size;
20078c2ecf20Sopenharmony_ci	if (var->bits_per_pixel == 1)
20088c2ecf20Sopenharmony_ci		info->fix.smem_len /= 4;
20098c2ecf20Sopenharmony_ci	info->fix.type_aux   = 0;
20108c2ecf20Sopenharmony_ci	info->fix.xpanstep   = 1;
20118c2ecf20Sopenharmony_ci	info->fix.ypanstep   = 1;
20128c2ecf20Sopenharmony_ci	info->fix.ywrapstep  = 0;
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	/* FIXME: map region at 0xB8000 if available, fill in here */
20158c2ecf20Sopenharmony_ci	info->fix.mmio_len   = 0;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	fb_alloc_cmap(&info->cmap, 256, 0);
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	return 0;
20208c2ecf20Sopenharmony_ci}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cistatic int cirrusfb_register(struct fb_info *info)
20238c2ecf20Sopenharmony_ci{
20248c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
20258c2ecf20Sopenharmony_ci	int err;
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	/* sanity checks */
20288c2ecf20Sopenharmony_ci	assert(cinfo->btype != BT_NONE);
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	/* set all the vital stuff */
20318c2ecf20Sopenharmony_ci	cirrusfb_set_fbinfo(info);
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci	dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
20368c2ecf20Sopenharmony_ci	if (!err) {
20378c2ecf20Sopenharmony_ci		dev_dbg(info->device, "wrong initial video mode\n");
20388c2ecf20Sopenharmony_ci		err = -EINVAL;
20398c2ecf20Sopenharmony_ci		goto err_dealloc_cmap;
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	info->var.activate = FB_ACTIVATE_NOW;
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	err = cirrusfb_check_var(&info->var, info);
20458c2ecf20Sopenharmony_ci	if (err < 0) {
20468c2ecf20Sopenharmony_ci		/* should never happen */
20478c2ecf20Sopenharmony_ci		dev_dbg(info->device,
20488c2ecf20Sopenharmony_ci			"choking on default var... umm, no good.\n");
20498c2ecf20Sopenharmony_ci		goto err_dealloc_cmap;
20508c2ecf20Sopenharmony_ci	}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	err = register_framebuffer(info);
20538c2ecf20Sopenharmony_ci	if (err < 0) {
20548c2ecf20Sopenharmony_ci		dev_err(info->device,
20558c2ecf20Sopenharmony_ci			"could not register fb device; err = %d!\n", err);
20568c2ecf20Sopenharmony_ci		goto err_dealloc_cmap;
20578c2ecf20Sopenharmony_ci	}
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	return 0;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_cierr_dealloc_cmap:
20628c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
20638c2ecf20Sopenharmony_ci	return err;
20648c2ecf20Sopenharmony_ci}
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_cistatic void cirrusfb_cleanup(struct fb_info *info)
20678c2ecf20Sopenharmony_ci{
20688c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo = info->par;
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	switch_monitor(cinfo, 0);
20718c2ecf20Sopenharmony_ci	unregister_framebuffer(info);
20728c2ecf20Sopenharmony_ci	fb_dealloc_cmap(&info->cmap);
20738c2ecf20Sopenharmony_ci	dev_dbg(info->device, "Framebuffer unregistered\n");
20748c2ecf20Sopenharmony_ci	cinfo->unmap(info);
20758c2ecf20Sopenharmony_ci	framebuffer_release(info);
20768c2ecf20Sopenharmony_ci}
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
20798c2ecf20Sopenharmony_cistatic int cirrusfb_pci_register(struct pci_dev *pdev,
20808c2ecf20Sopenharmony_ci				 const struct pci_device_id *ent)
20818c2ecf20Sopenharmony_ci{
20828c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo;
20838c2ecf20Sopenharmony_ci	struct fb_info *info;
20848c2ecf20Sopenharmony_ci	unsigned long board_addr, board_size;
20858c2ecf20Sopenharmony_ci	int ret;
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
20888c2ecf20Sopenharmony_ci	if (ret < 0) {
20898c2ecf20Sopenharmony_ci		printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
20908c2ecf20Sopenharmony_ci		goto err_out;
20918c2ecf20Sopenharmony_ci	}
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
20948c2ecf20Sopenharmony_ci	if (!info) {
20958c2ecf20Sopenharmony_ci		ret = -ENOMEM;
20968c2ecf20Sopenharmony_ci		goto err_out;
20978c2ecf20Sopenharmony_ci	}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_ci	cinfo = info->par;
21008c2ecf20Sopenharmony_ci	cinfo->btype = (enum cirrus_board) ent->driver_data;
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	dev_dbg(info->device,
21038c2ecf20Sopenharmony_ci		" Found PCI device, base address 0 is 0x%Lx, btype set to %d\n",
21048c2ecf20Sopenharmony_ci		(unsigned long long)pdev->resource[0].start,  cinfo->btype);
21058c2ecf20Sopenharmony_ci	dev_dbg(info->device, " base address 1 is 0x%Lx\n",
21068c2ecf20Sopenharmony_ci		(unsigned long long)pdev->resource[1].start);
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	dev_dbg(info->device,
21098c2ecf20Sopenharmony_ci		"Attempt to get PCI info for Cirrus Graphics Card\n");
21108c2ecf20Sopenharmony_ci	get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
21118c2ecf20Sopenharmony_ci	/* FIXME: this forces VGA.  alternatives? */
21128c2ecf20Sopenharmony_ci	cinfo->regbase = NULL;
21138c2ecf20Sopenharmony_ci	cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n",
21168c2ecf20Sopenharmony_ci		board_addr, info->fix.mmio_start);
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	board_size = (cinfo->btype == BT_GD5480) ?
21198c2ecf20Sopenharmony_ci		32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase);
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	ret = pci_request_regions(pdev, "cirrusfb");
21228c2ecf20Sopenharmony_ci	if (ret < 0) {
21238c2ecf20Sopenharmony_ci		dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
21248c2ecf20Sopenharmony_ci			board_addr);
21258c2ecf20Sopenharmony_ci		goto err_release_fb;
21268c2ecf20Sopenharmony_ci	}
21278c2ecf20Sopenharmony_ci#if 0 /* if the system didn't claim this region, we would... */
21288c2ecf20Sopenharmony_ci	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
21298c2ecf20Sopenharmony_ci		dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
21308c2ecf20Sopenharmony_ci			0xA0000L);
21318c2ecf20Sopenharmony_ci		ret = -EBUSY;
21328c2ecf20Sopenharmony_ci		goto err_release_regions;
21338c2ecf20Sopenharmony_ci	}
21348c2ecf20Sopenharmony_ci#endif
21358c2ecf20Sopenharmony_ci	if (request_region(0x3C0, 32, "cirrusfb"))
21368c2ecf20Sopenharmony_ci		release_io_ports = 1;
21378c2ecf20Sopenharmony_ci
21388c2ecf20Sopenharmony_ci	info->screen_base = ioremap(board_addr, board_size);
21398c2ecf20Sopenharmony_ci	if (!info->screen_base) {
21408c2ecf20Sopenharmony_ci		ret = -EIO;
21418c2ecf20Sopenharmony_ci		goto err_release_legacy;
21428c2ecf20Sopenharmony_ci	}
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	info->fix.smem_start = board_addr;
21458c2ecf20Sopenharmony_ci	info->screen_size = board_size;
21468c2ecf20Sopenharmony_ci	cinfo->unmap = cirrusfb_pci_unmap;
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	dev_info(info->device,
21498c2ecf20Sopenharmony_ci		 "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n",
21508c2ecf20Sopenharmony_ci		 info->screen_size >> 10, board_addr);
21518c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, info);
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci	ret = cirrusfb_register(info);
21548c2ecf20Sopenharmony_ci	if (!ret)
21558c2ecf20Sopenharmony_ci		return 0;
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	iounmap(info->screen_base);
21588c2ecf20Sopenharmony_cierr_release_legacy:
21598c2ecf20Sopenharmony_ci	if (release_io_ports)
21608c2ecf20Sopenharmony_ci		release_region(0x3C0, 32);
21618c2ecf20Sopenharmony_ci#if 0
21628c2ecf20Sopenharmony_ci	release_mem_region(0xA0000, 65535);
21638c2ecf20Sopenharmony_cierr_release_regions:
21648c2ecf20Sopenharmony_ci#endif
21658c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
21668c2ecf20Sopenharmony_cierr_release_fb:
21678c2ecf20Sopenharmony_ci	if (cinfo->laguna_mmio != NULL)
21688c2ecf20Sopenharmony_ci		iounmap(cinfo->laguna_mmio);
21698c2ecf20Sopenharmony_ci	framebuffer_release(info);
21708c2ecf20Sopenharmony_cierr_out:
21718c2ecf20Sopenharmony_ci	return ret;
21728c2ecf20Sopenharmony_ci}
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_cistatic void cirrusfb_pci_unregister(struct pci_dev *pdev)
21758c2ecf20Sopenharmony_ci{
21768c2ecf20Sopenharmony_ci	struct fb_info *info = pci_get_drvdata(pdev);
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	cirrusfb_cleanup(info);
21798c2ecf20Sopenharmony_ci}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_cistatic struct pci_driver cirrusfb_pci_driver = {
21828c2ecf20Sopenharmony_ci	.name		= "cirrusfb",
21838c2ecf20Sopenharmony_ci	.id_table	= cirrusfb_pci_table,
21848c2ecf20Sopenharmony_ci	.probe		= cirrusfb_pci_register,
21858c2ecf20Sopenharmony_ci	.remove		= cirrusfb_pci_unregister,
21868c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
21878c2ecf20Sopenharmony_ci#if 0
21888c2ecf20Sopenharmony_ci	.suspend	= cirrusfb_pci_suspend,
21898c2ecf20Sopenharmony_ci	.resume		= cirrusfb_pci_resume,
21908c2ecf20Sopenharmony_ci#endif
21918c2ecf20Sopenharmony_ci#endif
21928c2ecf20Sopenharmony_ci};
21938c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
21968c2ecf20Sopenharmony_cistatic int cirrusfb_zorro_register(struct zorro_dev *z,
21978c2ecf20Sopenharmony_ci				   const struct zorro_device_id *ent)
21988c2ecf20Sopenharmony_ci{
21998c2ecf20Sopenharmony_ci	struct fb_info *info;
22008c2ecf20Sopenharmony_ci	int error;
22018c2ecf20Sopenharmony_ci	const struct zorrocl *zcl;
22028c2ecf20Sopenharmony_ci	enum cirrus_board btype;
22038c2ecf20Sopenharmony_ci	unsigned long regbase, ramsize, rambase;
22048c2ecf20Sopenharmony_ci	struct cirrusfb_info *cinfo;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
22078c2ecf20Sopenharmony_ci	if (!info)
22088c2ecf20Sopenharmony_ci		return -ENOMEM;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	zcl = (const struct zorrocl *)ent->driver_data;
22118c2ecf20Sopenharmony_ci	btype = zcl->type;
22128c2ecf20Sopenharmony_ci	regbase = zorro_resource_start(z) + zcl->regoffset;
22138c2ecf20Sopenharmony_ci	ramsize = zcl->ramsize;
22148c2ecf20Sopenharmony_ci	if (ramsize) {
22158c2ecf20Sopenharmony_ci		rambase = zorro_resource_start(z) + zcl->ramoffset;
22168c2ecf20Sopenharmony_ci		if (zorro_resource_len(z) == 64 * MB_) {
22178c2ecf20Sopenharmony_ci			/* Quirk for 64 MiB Picasso IV */
22188c2ecf20Sopenharmony_ci			rambase += zcl->ramoffset;
22198c2ecf20Sopenharmony_ci		}
22208c2ecf20Sopenharmony_ci	} else {
22218c2ecf20Sopenharmony_ci		struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
22228c2ecf20Sopenharmony_ci		if (!ram || !zorro_resource_len(ram)) {
22238c2ecf20Sopenharmony_ci			dev_err(info->device, "No video RAM found\n");
22248c2ecf20Sopenharmony_ci			error = -ENODEV;
22258c2ecf20Sopenharmony_ci			goto err_release_fb;
22268c2ecf20Sopenharmony_ci		}
22278c2ecf20Sopenharmony_ci		rambase = zorro_resource_start(ram);
22288c2ecf20Sopenharmony_ci		ramsize = zorro_resource_len(ram);
22298c2ecf20Sopenharmony_ci		if (zcl->ramid2 &&
22308c2ecf20Sopenharmony_ci		    (ram = zorro_find_device(zcl->ramid2, NULL))) {
22318c2ecf20Sopenharmony_ci			if (zorro_resource_start(ram) != rambase + ramsize) {
22328c2ecf20Sopenharmony_ci				dev_warn(info->device,
22338c2ecf20Sopenharmony_ci					 "Skipping non-contiguous RAM at %pR\n",
22348c2ecf20Sopenharmony_ci					 &ram->resource);
22358c2ecf20Sopenharmony_ci			} else {
22368c2ecf20Sopenharmony_ci				ramsize += zorro_resource_len(ram);
22378c2ecf20Sopenharmony_ci			}
22388c2ecf20Sopenharmony_ci		}
22398c2ecf20Sopenharmony_ci	}
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	dev_info(info->device,
22428c2ecf20Sopenharmony_ci		 "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n",
22438c2ecf20Sopenharmony_ci		 cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
22448c2ecf20Sopenharmony_ci		 rambase);
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci	if (!zorro_request_device(z, "cirrusfb")) {
22478c2ecf20Sopenharmony_ci		dev_err(info->device, "Cannot reserve %pR\n", &z->resource);
22488c2ecf20Sopenharmony_ci		error = -EBUSY;
22498c2ecf20Sopenharmony_ci		goto err_release_fb;
22508c2ecf20Sopenharmony_ci	}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	cinfo = info->par;
22538c2ecf20Sopenharmony_ci	cinfo->btype = btype;
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	info->fix.mmio_start = regbase;
22568c2ecf20Sopenharmony_ci	cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
22578c2ecf20Sopenharmony_ci					    : ZTWO_VADDR(regbase);
22588c2ecf20Sopenharmony_ci	if (!cinfo->regbase) {
22598c2ecf20Sopenharmony_ci		dev_err(info->device, "Cannot map registers\n");
22608c2ecf20Sopenharmony_ci		error = -EIO;
22618c2ecf20Sopenharmony_ci		goto err_release_dev;
22628c2ecf20Sopenharmony_ci	}
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	info->fix.smem_start = rambase;
22658c2ecf20Sopenharmony_ci	info->screen_size = ramsize;
22668c2ecf20Sopenharmony_ci	info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
22678c2ecf20Sopenharmony_ci					       : ZTWO_VADDR(rambase);
22688c2ecf20Sopenharmony_ci	if (!info->screen_base) {
22698c2ecf20Sopenharmony_ci		dev_err(info->device, "Cannot map video RAM\n");
22708c2ecf20Sopenharmony_ci		error = -EIO;
22718c2ecf20Sopenharmony_ci		goto err_unmap_reg;
22728c2ecf20Sopenharmony_ci	}
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	cinfo->unmap = cirrusfb_zorro_unmap;
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	dev_info(info->device,
22778c2ecf20Sopenharmony_ci		 "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n",
22788c2ecf20Sopenharmony_ci		 ramsize / MB_, rambase);
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	/* MCLK select etc. */
22818c2ecf20Sopenharmony_ci	if (cirrusfb_board_info[btype].init_sr1f)
22828c2ecf20Sopenharmony_ci		vga_wseq(cinfo->regbase, CL_SEQR1F,
22838c2ecf20Sopenharmony_ci			 cirrusfb_board_info[btype].sr1f);
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	error = cirrusfb_register(info);
22868c2ecf20Sopenharmony_ci	if (error) {
22878c2ecf20Sopenharmony_ci		dev_err(info->device, "Failed to register device, error %d\n",
22888c2ecf20Sopenharmony_ci			error);
22898c2ecf20Sopenharmony_ci		goto err_unmap_ram;
22908c2ecf20Sopenharmony_ci	}
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci	zorro_set_drvdata(z, info);
22938c2ecf20Sopenharmony_ci	return 0;
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_cierr_unmap_ram:
22968c2ecf20Sopenharmony_ci	if (rambase > 16 * MB_)
22978c2ecf20Sopenharmony_ci		iounmap(info->screen_base);
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_cierr_unmap_reg:
23008c2ecf20Sopenharmony_ci	if (regbase > 16 * MB_)
23018c2ecf20Sopenharmony_ci		iounmap(cinfo->regbase);
23028c2ecf20Sopenharmony_cierr_release_dev:
23038c2ecf20Sopenharmony_ci	zorro_release_device(z);
23048c2ecf20Sopenharmony_cierr_release_fb:
23058c2ecf20Sopenharmony_ci	framebuffer_release(info);
23068c2ecf20Sopenharmony_ci	return error;
23078c2ecf20Sopenharmony_ci}
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_civoid cirrusfb_zorro_unregister(struct zorro_dev *z)
23108c2ecf20Sopenharmony_ci{
23118c2ecf20Sopenharmony_ci	struct fb_info *info = zorro_get_drvdata(z);
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	cirrusfb_cleanup(info);
23148c2ecf20Sopenharmony_ci	zorro_set_drvdata(z, NULL);
23158c2ecf20Sopenharmony_ci}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_cistatic struct zorro_driver cirrusfb_zorro_driver = {
23188c2ecf20Sopenharmony_ci	.name		= "cirrusfb",
23198c2ecf20Sopenharmony_ci	.id_table	= cirrusfb_zorro_table,
23208c2ecf20Sopenharmony_ci	.probe		= cirrusfb_zorro_register,
23218c2ecf20Sopenharmony_ci	.remove		= cirrusfb_zorro_unregister,
23228c2ecf20Sopenharmony_ci};
23238c2ecf20Sopenharmony_ci#endif /* CONFIG_ZORRO */
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci#ifndef MODULE
23268c2ecf20Sopenharmony_cistatic int __init cirrusfb_setup(char *options)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	char *this_opt;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	if (!options || !*options)
23318c2ecf20Sopenharmony_ci		return 0;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	while ((this_opt = strsep(&options, ",")) != NULL) {
23348c2ecf20Sopenharmony_ci		if (!*this_opt)
23358c2ecf20Sopenharmony_ci			continue;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci		if (!strcmp(this_opt, "noaccel"))
23388c2ecf20Sopenharmony_ci			noaccel = 1;
23398c2ecf20Sopenharmony_ci		else if (!strncmp(this_opt, "mode:", 5))
23408c2ecf20Sopenharmony_ci			mode_option = this_opt + 5;
23418c2ecf20Sopenharmony_ci		else
23428c2ecf20Sopenharmony_ci			mode_option = this_opt;
23438c2ecf20Sopenharmony_ci	}
23448c2ecf20Sopenharmony_ci	return 0;
23458c2ecf20Sopenharmony_ci}
23468c2ecf20Sopenharmony_ci#endif
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci    /*
23498c2ecf20Sopenharmony_ci     *  Modularization
23508c2ecf20Sopenharmony_ci     */
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
23538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
23548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_cistatic int __init cirrusfb_init(void)
23578c2ecf20Sopenharmony_ci{
23588c2ecf20Sopenharmony_ci	int error = 0;
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci#ifndef MODULE
23618c2ecf20Sopenharmony_ci	char *option = NULL;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	if (fb_get_options("cirrusfb", &option))
23648c2ecf20Sopenharmony_ci		return -ENODEV;
23658c2ecf20Sopenharmony_ci	cirrusfb_setup(option);
23668c2ecf20Sopenharmony_ci#endif
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
23698c2ecf20Sopenharmony_ci	error |= zorro_register_driver(&cirrusfb_zorro_driver);
23708c2ecf20Sopenharmony_ci#endif
23718c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
23728c2ecf20Sopenharmony_ci	error |= pci_register_driver(&cirrusfb_pci_driver);
23738c2ecf20Sopenharmony_ci#endif
23748c2ecf20Sopenharmony_ci	return error;
23758c2ecf20Sopenharmony_ci}
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_cistatic void __exit cirrusfb_exit(void)
23788c2ecf20Sopenharmony_ci{
23798c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI
23808c2ecf20Sopenharmony_ci	pci_unregister_driver(&cirrusfb_pci_driver);
23818c2ecf20Sopenharmony_ci#endif
23828c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
23838c2ecf20Sopenharmony_ci	zorro_unregister_driver(&cirrusfb_zorro_driver);
23848c2ecf20Sopenharmony_ci#endif
23858c2ecf20Sopenharmony_ci}
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_cimodule_init(cirrusfb_init);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_cimodule_param(mode_option, charp, 0);
23908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
23918c2ecf20Sopenharmony_cimodule_param(noaccel, bool, 0);
23928c2ecf20Sopenharmony_ciMODULE_PARM_DESC(noaccel, "Disable acceleration");
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci#ifdef MODULE
23958c2ecf20Sopenharmony_cimodule_exit(cirrusfb_exit);
23968c2ecf20Sopenharmony_ci#endif
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci/**********************************************************************/
23998c2ecf20Sopenharmony_ci/* about the following functions - I have used the same names for the */
24008c2ecf20Sopenharmony_ci/* functions as Markus Wild did in his Retina driver for NetBSD as    */
24018c2ecf20Sopenharmony_ci/* they just made sense for this purpose. Apart from that, I wrote    */
24028c2ecf20Sopenharmony_ci/* these functions myself.					    */
24038c2ecf20Sopenharmony_ci/**********************************************************************/
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci/*** WGen() - write into one of the external/general registers ***/
24068c2ecf20Sopenharmony_cistatic void WGen(const struct cirrusfb_info *cinfo,
24078c2ecf20Sopenharmony_ci		  int regnum, unsigned char val)
24088c2ecf20Sopenharmony_ci{
24098c2ecf20Sopenharmony_ci	unsigned long regofs = 0;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
24128c2ecf20Sopenharmony_ci		/* Picasso II specific hack */
24138c2ecf20Sopenharmony_ci/*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
24148c2ecf20Sopenharmony_ci		  regnum == CL_VSSM2) */
24158c2ecf20Sopenharmony_ci		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
24168c2ecf20Sopenharmony_ci			regofs = 0xfff;
24178c2ecf20Sopenharmony_ci	}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	vga_w(cinfo->regbase, regofs + regnum, val);
24208c2ecf20Sopenharmony_ci}
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci/*** RGen() - read out one of the external/general registers ***/
24238c2ecf20Sopenharmony_cistatic unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
24248c2ecf20Sopenharmony_ci{
24258c2ecf20Sopenharmony_ci	unsigned long regofs = 0;
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
24288c2ecf20Sopenharmony_ci		/* Picasso II specific hack */
24298c2ecf20Sopenharmony_ci/*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
24308c2ecf20Sopenharmony_ci		  regnum == CL_VSSM2) */
24318c2ecf20Sopenharmony_ci		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
24328c2ecf20Sopenharmony_ci			regofs = 0xfff;
24338c2ecf20Sopenharmony_ci	}
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci	return vga_r(cinfo->regbase, regofs + regnum);
24368c2ecf20Sopenharmony_ci}
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
24398c2ecf20Sopenharmony_cistatic void AttrOn(const struct cirrusfb_info *cinfo)
24408c2ecf20Sopenharmony_ci{
24418c2ecf20Sopenharmony_ci	assert(cinfo != NULL);
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
24448c2ecf20Sopenharmony_ci		/* if we're just in "write value" mode, write back the */
24458c2ecf20Sopenharmony_ci		/* same value as before to not modify anything */
24468c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, VGA_ATT_IW,
24478c2ecf20Sopenharmony_ci		      vga_r(cinfo->regbase, VGA_ATT_R));
24488c2ecf20Sopenharmony_ci	}
24498c2ecf20Sopenharmony_ci	/* turn on video bit */
24508c2ecf20Sopenharmony_ci/*      vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
24518c2ecf20Sopenharmony_ci	vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	/* dummy write on Reg0 to be on "write index" mode next time */
24548c2ecf20Sopenharmony_ci	vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
24558c2ecf20Sopenharmony_ci}
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci/*** WHDR() - write into the Hidden DAC register ***/
24588c2ecf20Sopenharmony_ci/* as the HDR is the only extension register that requires special treatment
24598c2ecf20Sopenharmony_ci * (the other extension registers are accessible just like the "ordinary"
24608c2ecf20Sopenharmony_ci * registers of their functional group) here is a specialized routine for
24618c2ecf20Sopenharmony_ci * accessing the HDR
24628c2ecf20Sopenharmony_ci */
24638c2ecf20Sopenharmony_cistatic void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
24648c2ecf20Sopenharmony_ci{
24658c2ecf20Sopenharmony_ci	unsigned char dummy;
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	if (is_laguna(cinfo))
24688c2ecf20Sopenharmony_ci		return;
24698c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
24708c2ecf20Sopenharmony_ci		/* Klaus' hint for correct access to HDR on some boards */
24718c2ecf20Sopenharmony_ci		/* first write 0 to pixel mask (3c6) */
24728c2ecf20Sopenharmony_ci		WGen(cinfo, VGA_PEL_MSK, 0x00);
24738c2ecf20Sopenharmony_ci		udelay(200);
24748c2ecf20Sopenharmony_ci		/* next read dummy from pixel address (3c8) */
24758c2ecf20Sopenharmony_ci		dummy = RGen(cinfo, VGA_PEL_IW);
24768c2ecf20Sopenharmony_ci		udelay(200);
24778c2ecf20Sopenharmony_ci	}
24788c2ecf20Sopenharmony_ci	/* now do the usual stuff to access the HDR */
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	dummy = RGen(cinfo, VGA_PEL_MSK);
24818c2ecf20Sopenharmony_ci	udelay(200);
24828c2ecf20Sopenharmony_ci	dummy = RGen(cinfo, VGA_PEL_MSK);
24838c2ecf20Sopenharmony_ci	udelay(200);
24848c2ecf20Sopenharmony_ci	dummy = RGen(cinfo, VGA_PEL_MSK);
24858c2ecf20Sopenharmony_ci	udelay(200);
24868c2ecf20Sopenharmony_ci	dummy = RGen(cinfo, VGA_PEL_MSK);
24878c2ecf20Sopenharmony_ci	udelay(200);
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	WGen(cinfo, VGA_PEL_MSK, val);
24908c2ecf20Sopenharmony_ci	udelay(200);
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO) {
24938c2ecf20Sopenharmony_ci		/* now first reset HDR access counter */
24948c2ecf20Sopenharmony_ci		dummy = RGen(cinfo, VGA_PEL_IW);
24958c2ecf20Sopenharmony_ci		udelay(200);
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci		/* and at the end, restore the mask value */
24988c2ecf20Sopenharmony_ci		/* ## is this mask always 0xff? */
24998c2ecf20Sopenharmony_ci		WGen(cinfo, VGA_PEL_MSK, 0xff);
25008c2ecf20Sopenharmony_ci		udelay(200);
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci}
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci/*** WSFR() - write to the "special function register" (SFR) ***/
25058c2ecf20Sopenharmony_cistatic void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
25068c2ecf20Sopenharmony_ci{
25078c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
25088c2ecf20Sopenharmony_ci	assert(cinfo->regbase != NULL);
25098c2ecf20Sopenharmony_ci	cinfo->SFR = val;
25108c2ecf20Sopenharmony_ci	z_writeb(val, cinfo->regbase + 0x8000);
25118c2ecf20Sopenharmony_ci#endif
25128c2ecf20Sopenharmony_ci}
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci/* The Picasso has a second register for switching the monitor bit */
25158c2ecf20Sopenharmony_cistatic void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
25168c2ecf20Sopenharmony_ci{
25178c2ecf20Sopenharmony_ci#ifdef CONFIG_ZORRO
25188c2ecf20Sopenharmony_ci	/* writing an arbitrary value to this one causes the monitor switcher */
25198c2ecf20Sopenharmony_ci	/* to flip to Amiga display */
25208c2ecf20Sopenharmony_ci	assert(cinfo->regbase != NULL);
25218c2ecf20Sopenharmony_ci	cinfo->SFR = val;
25228c2ecf20Sopenharmony_ci	z_writeb(val, cinfo->regbase + 0x9000);
25238c2ecf20Sopenharmony_ci#endif
25248c2ecf20Sopenharmony_ci}
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci/*** WClut - set CLUT entry (range: 0..63) ***/
25278c2ecf20Sopenharmony_cistatic void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
25288c2ecf20Sopenharmony_ci	    unsigned char green, unsigned char blue)
25298c2ecf20Sopenharmony_ci{
25308c2ecf20Sopenharmony_ci	unsigned int data = VGA_PEL_D;
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	/* address write mode register is not translated.. */
25338c2ecf20Sopenharmony_ci	vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
25368c2ecf20Sopenharmony_ci	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 ||
25378c2ecf20Sopenharmony_ci	    cinfo->btype == BT_SD64 || is_laguna(cinfo)) {
25388c2ecf20Sopenharmony_ci		/* but DAC data register IS, at least for Picasso II */
25398c2ecf20Sopenharmony_ci		if (cinfo->btype == BT_PICASSO)
25408c2ecf20Sopenharmony_ci			data += 0xfff;
25418c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, data, red);
25428c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, data, green);
25438c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, data, blue);
25448c2ecf20Sopenharmony_ci	} else {
25458c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, data, blue);
25468c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, data, green);
25478c2ecf20Sopenharmony_ci		vga_w(cinfo->regbase, data, red);
25488c2ecf20Sopenharmony_ci	}
25498c2ecf20Sopenharmony_ci}
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci#if 0
25528c2ecf20Sopenharmony_ci/*** RClut - read CLUT entry (range 0..63) ***/
25538c2ecf20Sopenharmony_cistatic void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
25548c2ecf20Sopenharmony_ci	    unsigned char *green, unsigned char *blue)
25558c2ecf20Sopenharmony_ci{
25568c2ecf20Sopenharmony_ci	unsigned int data = VGA_PEL_D;
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci	vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
25618c2ecf20Sopenharmony_ci	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
25628c2ecf20Sopenharmony_ci		if (cinfo->btype == BT_PICASSO)
25638c2ecf20Sopenharmony_ci			data += 0xfff;
25648c2ecf20Sopenharmony_ci		*red = vga_r(cinfo->regbase, data);
25658c2ecf20Sopenharmony_ci		*green = vga_r(cinfo->regbase, data);
25668c2ecf20Sopenharmony_ci		*blue = vga_r(cinfo->regbase, data);
25678c2ecf20Sopenharmony_ci	} else {
25688c2ecf20Sopenharmony_ci		*blue = vga_r(cinfo->regbase, data);
25698c2ecf20Sopenharmony_ci		*green = vga_r(cinfo->regbase, data);
25708c2ecf20Sopenharmony_ci		*red = vga_r(cinfo->regbase, data);
25718c2ecf20Sopenharmony_ci	}
25728c2ecf20Sopenharmony_ci}
25738c2ecf20Sopenharmony_ci#endif
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci/*******************************************************************
25768c2ecf20Sopenharmony_ci	cirrusfb_WaitBLT()
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	Wait for the BitBLT engine to complete a possible earlier job
25798c2ecf20Sopenharmony_ci*********************************************************************/
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci/* FIXME: use interrupts instead */
25828c2ecf20Sopenharmony_cistatic void cirrusfb_WaitBLT(u8 __iomem *regbase)
25838c2ecf20Sopenharmony_ci{
25848c2ecf20Sopenharmony_ci	while (vga_rgfx(regbase, CL_GR31) & 0x08)
25858c2ecf20Sopenharmony_ci		cpu_relax();
25868c2ecf20Sopenharmony_ci}
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci/*******************************************************************
25898c2ecf20Sopenharmony_ci	cirrusfb_BitBLT()
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	perform accelerated "scrolling"
25928c2ecf20Sopenharmony_ci********************************************************************/
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_cistatic void cirrusfb_set_blitter(u8 __iomem *regbase,
25958c2ecf20Sopenharmony_ci			    u_short nwidth, u_short nheight,
25968c2ecf20Sopenharmony_ci			    u_long nsrc, u_long ndest,
25978c2ecf20Sopenharmony_ci			    u_short bltmode, u_short line_length)
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci{
26008c2ecf20Sopenharmony_ci	/* pitch: set to line_length */
26018c2ecf20Sopenharmony_ci	/* dest pitch low */
26028c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR24, line_length & 0xff);
26038c2ecf20Sopenharmony_ci	/* dest pitch hi */
26048c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR25, line_length >> 8);
26058c2ecf20Sopenharmony_ci	/* source pitch low */
26068c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR26, line_length & 0xff);
26078c2ecf20Sopenharmony_ci	/* source pitch hi */
26088c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR27, line_length >> 8);
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	/* BLT width: actual number of pixels - 1 */
26118c2ecf20Sopenharmony_ci	/* BLT width low */
26128c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
26138c2ecf20Sopenharmony_ci	/* BLT width hi */
26148c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR21, nwidth >> 8);
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci	/* BLT height: actual number of lines -1 */
26178c2ecf20Sopenharmony_ci	/* BLT height low */
26188c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR22, nheight & 0xff);
26198c2ecf20Sopenharmony_ci	/* BLT width hi */
26208c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR23, nheight >> 8);
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	/* BLT destination */
26238c2ecf20Sopenharmony_ci	/* BLT dest low */
26248c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
26258c2ecf20Sopenharmony_ci	/* BLT dest mid */
26268c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
26278c2ecf20Sopenharmony_ci	/* BLT dest hi */
26288c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	/* BLT source */
26318c2ecf20Sopenharmony_ci	/* BLT src low */
26328c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
26338c2ecf20Sopenharmony_ci	/* BLT src mid */
26348c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
26358c2ecf20Sopenharmony_ci	/* BLT src hi */
26368c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	/* BLT mode */
26398c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR30, bltmode);	/* BLT mode */
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci	/* BLT ROP: SrcCopy */
26428c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR32, 0x0d);	/* BLT ROP */
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	/* and finally: GO! */
26458c2ecf20Sopenharmony_ci	vga_wgfx(regbase, CL_GR31, 0x02);	/* BLT Start/status */
26468c2ecf20Sopenharmony_ci}
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci/*******************************************************************
26498c2ecf20Sopenharmony_ci	cirrusfb_BitBLT()
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci	perform accelerated "scrolling"
26528c2ecf20Sopenharmony_ci********************************************************************/
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_cistatic void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
26558c2ecf20Sopenharmony_ci			    u_short curx, u_short cury,
26568c2ecf20Sopenharmony_ci			    u_short destx, u_short desty,
26578c2ecf20Sopenharmony_ci			    u_short width, u_short height,
26588c2ecf20Sopenharmony_ci			    u_short line_length)
26598c2ecf20Sopenharmony_ci{
26608c2ecf20Sopenharmony_ci	u_short nwidth = width - 1;
26618c2ecf20Sopenharmony_ci	u_short nheight = height - 1;
26628c2ecf20Sopenharmony_ci	u_long nsrc, ndest;
26638c2ecf20Sopenharmony_ci	u_char bltmode;
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	bltmode = 0x00;
26668c2ecf20Sopenharmony_ci	/* if source adr < dest addr, do the Blt backwards */
26678c2ecf20Sopenharmony_ci	if (cury <= desty) {
26688c2ecf20Sopenharmony_ci		if (cury == desty) {
26698c2ecf20Sopenharmony_ci			/* if src and dest are on the same line, check x */
26708c2ecf20Sopenharmony_ci			if (curx < destx)
26718c2ecf20Sopenharmony_ci				bltmode |= 0x01;
26728c2ecf20Sopenharmony_ci		} else
26738c2ecf20Sopenharmony_ci			bltmode |= 0x01;
26748c2ecf20Sopenharmony_ci	}
26758c2ecf20Sopenharmony_ci	/* standard case: forward blitting */
26768c2ecf20Sopenharmony_ci	nsrc = (cury * line_length) + curx;
26778c2ecf20Sopenharmony_ci	ndest = (desty * line_length) + destx;
26788c2ecf20Sopenharmony_ci	if (bltmode) {
26798c2ecf20Sopenharmony_ci		/* this means start addresses are at the end,
26808c2ecf20Sopenharmony_ci		 * counting backwards
26818c2ecf20Sopenharmony_ci		 */
26828c2ecf20Sopenharmony_ci		nsrc += nheight * line_length + nwidth;
26838c2ecf20Sopenharmony_ci		ndest += nheight * line_length + nwidth;
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	cirrusfb_WaitBLT(regbase);
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	cirrusfb_set_blitter(regbase, nwidth, nheight,
26898c2ecf20Sopenharmony_ci			    nsrc, ndest, bltmode, line_length);
26908c2ecf20Sopenharmony_ci}
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci/*******************************************************************
26938c2ecf20Sopenharmony_ci	cirrusfb_RectFill()
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	perform accelerated rectangle fill
26968c2ecf20Sopenharmony_ci********************************************************************/
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_cistatic void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
26998c2ecf20Sopenharmony_ci		     u_short x, u_short y, u_short width, u_short height,
27008c2ecf20Sopenharmony_ci		     u32 fg_color, u32 bg_color, u_short line_length,
27018c2ecf20Sopenharmony_ci		     u_char blitmode)
27028c2ecf20Sopenharmony_ci{
27038c2ecf20Sopenharmony_ci	u_long ndest = (y * line_length) + x;
27048c2ecf20Sopenharmony_ci	u_char op;
27058c2ecf20Sopenharmony_ci
27068c2ecf20Sopenharmony_ci	cirrusfb_WaitBLT(regbase);
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	/* This is a ColorExpand Blt, using the */
27098c2ecf20Sopenharmony_ci	/* same color for foreground and background */
27108c2ecf20Sopenharmony_ci	vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color);
27118c2ecf20Sopenharmony_ci	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color);
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	op = 0x80;
27148c2ecf20Sopenharmony_ci	if (bits_per_pixel >= 16) {
27158c2ecf20Sopenharmony_ci		vga_wgfx(regbase, CL_GR10, bg_color >> 8);
27168c2ecf20Sopenharmony_ci		vga_wgfx(regbase, CL_GR11, fg_color >> 8);
27178c2ecf20Sopenharmony_ci		op = 0x90;
27188c2ecf20Sopenharmony_ci	}
27198c2ecf20Sopenharmony_ci	if (bits_per_pixel >= 24) {
27208c2ecf20Sopenharmony_ci		vga_wgfx(regbase, CL_GR12, bg_color >> 16);
27218c2ecf20Sopenharmony_ci		vga_wgfx(regbase, CL_GR13, fg_color >> 16);
27228c2ecf20Sopenharmony_ci		op = 0xa0;
27238c2ecf20Sopenharmony_ci	}
27248c2ecf20Sopenharmony_ci	if (bits_per_pixel == 32) {
27258c2ecf20Sopenharmony_ci		vga_wgfx(regbase, CL_GR14, bg_color >> 24);
27268c2ecf20Sopenharmony_ci		vga_wgfx(regbase, CL_GR15, fg_color >> 24);
27278c2ecf20Sopenharmony_ci		op = 0xb0;
27288c2ecf20Sopenharmony_ci	}
27298c2ecf20Sopenharmony_ci	cirrusfb_set_blitter(regbase, width - 1, height - 1,
27308c2ecf20Sopenharmony_ci			    0, ndest, op | blitmode, line_length);
27318c2ecf20Sopenharmony_ci}
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci/**************************************************************************
27348c2ecf20Sopenharmony_ci * bestclock() - determine closest possible clock lower(?) than the
27358c2ecf20Sopenharmony_ci * desired pixel clock
27368c2ecf20Sopenharmony_ci **************************************************************************/
27378c2ecf20Sopenharmony_cistatic void bestclock(long freq, int *nom, int *den, int *div)
27388c2ecf20Sopenharmony_ci{
27398c2ecf20Sopenharmony_ci	int n, d;
27408c2ecf20Sopenharmony_ci	long h, diff;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci	assert(nom != NULL);
27438c2ecf20Sopenharmony_ci	assert(den != NULL);
27448c2ecf20Sopenharmony_ci	assert(div != NULL);
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci	*nom = 0;
27478c2ecf20Sopenharmony_ci	*den = 0;
27488c2ecf20Sopenharmony_ci	*div = 0;
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	if (freq < 8000)
27518c2ecf20Sopenharmony_ci		freq = 8000;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	diff = freq;
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci	for (n = 32; n < 128; n++) {
27568c2ecf20Sopenharmony_ci		int s = 0;
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci		d = (14318 * n) / freq;
27598c2ecf20Sopenharmony_ci		if ((d >= 7) && (d <= 63)) {
27608c2ecf20Sopenharmony_ci			int temp = d;
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci			if (temp > 31) {
27638c2ecf20Sopenharmony_ci				s = 1;
27648c2ecf20Sopenharmony_ci				temp >>= 1;
27658c2ecf20Sopenharmony_ci			}
27668c2ecf20Sopenharmony_ci			h = ((14318 * n) / temp) >> s;
27678c2ecf20Sopenharmony_ci			h = h > freq ? h - freq : freq - h;
27688c2ecf20Sopenharmony_ci			if (h < diff) {
27698c2ecf20Sopenharmony_ci				diff = h;
27708c2ecf20Sopenharmony_ci				*nom = n;
27718c2ecf20Sopenharmony_ci				*den = temp;
27728c2ecf20Sopenharmony_ci				*div = s;
27738c2ecf20Sopenharmony_ci			}
27748c2ecf20Sopenharmony_ci		}
27758c2ecf20Sopenharmony_ci		d++;
27768c2ecf20Sopenharmony_ci		if ((d >= 7) && (d <= 63)) {
27778c2ecf20Sopenharmony_ci			if (d > 31) {
27788c2ecf20Sopenharmony_ci				s = 1;
27798c2ecf20Sopenharmony_ci				d >>= 1;
27808c2ecf20Sopenharmony_ci			}
27818c2ecf20Sopenharmony_ci			h = ((14318 * n) / d) >> s;
27828c2ecf20Sopenharmony_ci			h = h > freq ? h - freq : freq - h;
27838c2ecf20Sopenharmony_ci			if (h < diff) {
27848c2ecf20Sopenharmony_ci				diff = h;
27858c2ecf20Sopenharmony_ci				*nom = n;
27868c2ecf20Sopenharmony_ci				*den = d;
27878c2ecf20Sopenharmony_ci				*div = s;
27888c2ecf20Sopenharmony_ci			}
27898c2ecf20Sopenharmony_ci		}
27908c2ecf20Sopenharmony_ci	}
27918c2ecf20Sopenharmony_ci}
27928c2ecf20Sopenharmony_ci
27938c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------
27948c2ecf20Sopenharmony_ci *
27958c2ecf20Sopenharmony_ci * debugging functions
27968c2ecf20Sopenharmony_ci *
27978c2ecf20Sopenharmony_ci * -------------------------------------------------------------------------
27988c2ecf20Sopenharmony_ci */
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci#ifdef CIRRUSFB_DEBUG
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci/**
28038c2ecf20Sopenharmony_ci * cirrusfb_dbg_print_regs
28048c2ecf20Sopenharmony_ci * @base: If using newmmio, the newmmio base address, otherwise %NULL
28058c2ecf20Sopenharmony_ci * @reg_class: type of registers to read: %CRT, or %SEQ
28068c2ecf20Sopenharmony_ci *
28078c2ecf20Sopenharmony_ci * DESCRIPTION:
28088c2ecf20Sopenharmony_ci * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
28098c2ecf20Sopenharmony_ci * old-style I/O ports are queried for information, otherwise MMIO is
28108c2ecf20Sopenharmony_ci * used at the given @base address to query the information.
28118c2ecf20Sopenharmony_ci */
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_cistatic void cirrusfb_dbg_print_regs(struct fb_info *info,
28148c2ecf20Sopenharmony_ci				    caddr_t regbase,
28158c2ecf20Sopenharmony_ci				    enum cirrusfb_dbg_reg_class reg_class, ...)
28168c2ecf20Sopenharmony_ci{
28178c2ecf20Sopenharmony_ci	va_list list;
28188c2ecf20Sopenharmony_ci	unsigned char val = 0;
28198c2ecf20Sopenharmony_ci	unsigned reg;
28208c2ecf20Sopenharmony_ci	char *name;
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	va_start(list, reg_class);
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	name = va_arg(list, char *);
28258c2ecf20Sopenharmony_ci	while (name != NULL) {
28268c2ecf20Sopenharmony_ci		reg = va_arg(list, int);
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci		switch (reg_class) {
28298c2ecf20Sopenharmony_ci		case CRT:
28308c2ecf20Sopenharmony_ci			val = vga_rcrt(regbase, (unsigned char) reg);
28318c2ecf20Sopenharmony_ci			break;
28328c2ecf20Sopenharmony_ci		case SEQ:
28338c2ecf20Sopenharmony_ci			val = vga_rseq(regbase, (unsigned char) reg);
28348c2ecf20Sopenharmony_ci			break;
28358c2ecf20Sopenharmony_ci		default:
28368c2ecf20Sopenharmony_ci			/* should never occur */
28378c2ecf20Sopenharmony_ci			assert(false);
28388c2ecf20Sopenharmony_ci			break;
28398c2ecf20Sopenharmony_ci		}
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci		dev_dbg(info->device, "%8s = 0x%02X\n", name, val);
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci		name = va_arg(list, char *);
28448c2ecf20Sopenharmony_ci	}
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	va_end(list);
28478c2ecf20Sopenharmony_ci}
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci/**
28508c2ecf20Sopenharmony_ci * cirrusfb_dbg_reg_dump
28518c2ecf20Sopenharmony_ci * @base: If using newmmio, the newmmio base address, otherwise %NULL
28528c2ecf20Sopenharmony_ci *
28538c2ecf20Sopenharmony_ci * DESCRIPTION:
28548c2ecf20Sopenharmony_ci * Dumps a list of interesting VGA and CIRRUSFB registers.  If @base is %NULL,
28558c2ecf20Sopenharmony_ci * old-style I/O ports are queried for information, otherwise MMIO is
28568c2ecf20Sopenharmony_ci * used at the given @base address to query the information.
28578c2ecf20Sopenharmony_ci */
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_cistatic void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
28608c2ecf20Sopenharmony_ci{
28618c2ecf20Sopenharmony_ci	dev_dbg(info->device, "VGA CRTC register dump:\n");
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci	cirrusfb_dbg_print_regs(info, regbase, CRT,
28648c2ecf20Sopenharmony_ci			   "CR00", 0x00,
28658c2ecf20Sopenharmony_ci			   "CR01", 0x01,
28668c2ecf20Sopenharmony_ci			   "CR02", 0x02,
28678c2ecf20Sopenharmony_ci			   "CR03", 0x03,
28688c2ecf20Sopenharmony_ci			   "CR04", 0x04,
28698c2ecf20Sopenharmony_ci			   "CR05", 0x05,
28708c2ecf20Sopenharmony_ci			   "CR06", 0x06,
28718c2ecf20Sopenharmony_ci			   "CR07", 0x07,
28728c2ecf20Sopenharmony_ci			   "CR08", 0x08,
28738c2ecf20Sopenharmony_ci			   "CR09", 0x09,
28748c2ecf20Sopenharmony_ci			   "CR0A", 0x0A,
28758c2ecf20Sopenharmony_ci			   "CR0B", 0x0B,
28768c2ecf20Sopenharmony_ci			   "CR0C", 0x0C,
28778c2ecf20Sopenharmony_ci			   "CR0D", 0x0D,
28788c2ecf20Sopenharmony_ci			   "CR0E", 0x0E,
28798c2ecf20Sopenharmony_ci			   "CR0F", 0x0F,
28808c2ecf20Sopenharmony_ci			   "CR10", 0x10,
28818c2ecf20Sopenharmony_ci			   "CR11", 0x11,
28828c2ecf20Sopenharmony_ci			   "CR12", 0x12,
28838c2ecf20Sopenharmony_ci			   "CR13", 0x13,
28848c2ecf20Sopenharmony_ci			   "CR14", 0x14,
28858c2ecf20Sopenharmony_ci			   "CR15", 0x15,
28868c2ecf20Sopenharmony_ci			   "CR16", 0x16,
28878c2ecf20Sopenharmony_ci			   "CR17", 0x17,
28888c2ecf20Sopenharmony_ci			   "CR18", 0x18,
28898c2ecf20Sopenharmony_ci			   "CR22", 0x22,
28908c2ecf20Sopenharmony_ci			   "CR24", 0x24,
28918c2ecf20Sopenharmony_ci			   "CR26", 0x26,
28928c2ecf20Sopenharmony_ci			   "CR2D", 0x2D,
28938c2ecf20Sopenharmony_ci			   "CR2E", 0x2E,
28948c2ecf20Sopenharmony_ci			   "CR2F", 0x2F,
28958c2ecf20Sopenharmony_ci			   "CR30", 0x30,
28968c2ecf20Sopenharmony_ci			   "CR31", 0x31,
28978c2ecf20Sopenharmony_ci			   "CR32", 0x32,
28988c2ecf20Sopenharmony_ci			   "CR33", 0x33,
28998c2ecf20Sopenharmony_ci			   "CR34", 0x34,
29008c2ecf20Sopenharmony_ci			   "CR35", 0x35,
29018c2ecf20Sopenharmony_ci			   "CR36", 0x36,
29028c2ecf20Sopenharmony_ci			   "CR37", 0x37,
29038c2ecf20Sopenharmony_ci			   "CR38", 0x38,
29048c2ecf20Sopenharmony_ci			   "CR39", 0x39,
29058c2ecf20Sopenharmony_ci			   "CR3A", 0x3A,
29068c2ecf20Sopenharmony_ci			   "CR3B", 0x3B,
29078c2ecf20Sopenharmony_ci			   "CR3C", 0x3C,
29088c2ecf20Sopenharmony_ci			   "CR3D", 0x3D,
29098c2ecf20Sopenharmony_ci			   "CR3E", 0x3E,
29108c2ecf20Sopenharmony_ci			   "CR3F", 0x3F,
29118c2ecf20Sopenharmony_ci			   NULL);
29128c2ecf20Sopenharmony_ci
29138c2ecf20Sopenharmony_ci	dev_dbg(info->device, "\n");
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci	dev_dbg(info->device, "VGA SEQ register dump:\n");
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	cirrusfb_dbg_print_regs(info, regbase, SEQ,
29188c2ecf20Sopenharmony_ci			   "SR00", 0x00,
29198c2ecf20Sopenharmony_ci			   "SR01", 0x01,
29208c2ecf20Sopenharmony_ci			   "SR02", 0x02,
29218c2ecf20Sopenharmony_ci			   "SR03", 0x03,
29228c2ecf20Sopenharmony_ci			   "SR04", 0x04,
29238c2ecf20Sopenharmony_ci			   "SR08", 0x08,
29248c2ecf20Sopenharmony_ci			   "SR09", 0x09,
29258c2ecf20Sopenharmony_ci			   "SR0A", 0x0A,
29268c2ecf20Sopenharmony_ci			   "SR0B", 0x0B,
29278c2ecf20Sopenharmony_ci			   "SR0D", 0x0D,
29288c2ecf20Sopenharmony_ci			   "SR10", 0x10,
29298c2ecf20Sopenharmony_ci			   "SR11", 0x11,
29308c2ecf20Sopenharmony_ci			   "SR12", 0x12,
29318c2ecf20Sopenharmony_ci			   "SR13", 0x13,
29328c2ecf20Sopenharmony_ci			   "SR14", 0x14,
29338c2ecf20Sopenharmony_ci			   "SR15", 0x15,
29348c2ecf20Sopenharmony_ci			   "SR16", 0x16,
29358c2ecf20Sopenharmony_ci			   "SR17", 0x17,
29368c2ecf20Sopenharmony_ci			   "SR18", 0x18,
29378c2ecf20Sopenharmony_ci			   "SR19", 0x19,
29388c2ecf20Sopenharmony_ci			   "SR1A", 0x1A,
29398c2ecf20Sopenharmony_ci			   "SR1B", 0x1B,
29408c2ecf20Sopenharmony_ci			   "SR1C", 0x1C,
29418c2ecf20Sopenharmony_ci			   "SR1D", 0x1D,
29428c2ecf20Sopenharmony_ci			   "SR1E", 0x1E,
29438c2ecf20Sopenharmony_ci			   "SR1F", 0x1F,
29448c2ecf20Sopenharmony_ci			   NULL);
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	dev_dbg(info->device, "\n");
29478c2ecf20Sopenharmony_ci}
29488c2ecf20Sopenharmony_ci
29498c2ecf20Sopenharmony_ci#endif				/* CIRRUSFB_DEBUG */
29508c2ecf20Sopenharmony_ci
2951