linux/drivers/video/fbdev/cirrusfb.c

/*
 * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
 *
 * Copyright 1999-2001 Jeff Garzik <[email protected]>
 *
 * Contributors (thanks, all!)
 *
 *	David Eger:
 *	Overhaul for Linux 2.6
 *
 *      Jeff Rugen:
 *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
 *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
 *
 *	Geert Uytterhoeven:
 *	Excellent code review.
 *
 *	Lars Hecking:
 *	Amiga updates and testing.
 *
 * Original cirrusfb author:  Frank Neumann
 *
 * Based on retz3fb.c and cirrusfb.c:
 *      Copyright (C) 1997 Jes Sorensen
 *      Copyright (C) 1996 Frank Neumann
 *
 ***************************************************************
 *
 * Format this code with GNU indent '-kr -i8 -pcs' options.
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 *
 */

#include <linux/aperture.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>

#ifdef CONFIG_ZORRO
#include <linux/zorro.h>
#endif
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
#ifdef CONFIG_AMIGA
#include <asm/amigahw.h>
#endif

#include <video/vga.h>
#include <video/cirrus.h>

/*****************************************************************
 *
 * debugging and utility macros
 *
 */

/* disable runtime assertions? */
/* #define CIRRUSFB_NDEBUG */

/* debugging assertions */
#ifndef CIRRUSFB_NDEBUG
#define assert(expr)
#else
#define assert
#endif

#define MB_

/*****************************************************************
 *
 * chipset information
 *
 */

/* board types */
enum cirrus_board {};

/*
 * per-board-type information, used for enumerating and abstracting
 * chip-specific information
 * NOTE: MUST be in the same order as enum cirrus_board in order to
 * use direct indexing on this array
 * NOTE: '__initdata' cannot be used as some of this info
 * is required at runtime.  Maybe separate into an init-only and
 * a run-time table?
 */
static const struct cirrusfb_board_info_rec {} cirrusfb_board_info[] =;

#ifdef CONFIG_PCI
#define CHIP

static struct pci_device_id cirrusfb_pci_table[] =;
MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
#undef CHIP
#endif /* CONFIG_PCI */

#ifdef CONFIG_ZORRO
struct zorrocl {
	enum cirrus_board type;	/* Board type */
	u32 regoffset;		/* Offset of registers in first Zorro device */
	u32 ramsize;		/* Size of video RAM in first Zorro device */
				/* If zero, use autoprobe on RAM device */
	u32 ramoffset;		/* Offset of video RAM in first Zorro device */
	zorro_id ramid;		/* Zorro ID of RAM device */
	zorro_id ramid2;	/* Zorro ID of optional second RAM device */
};

static const struct zorrocl zcl_sd64 = {
	.type		= BT_SD64,
	.ramid		= ZORRO_PROD_HELFRICH_SD64_RAM,
};

static const struct zorrocl zcl_piccolo = {
	.type		= BT_PICCOLO,
	.ramid		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
};

static const struct zorrocl zcl_picasso = {
	.type		= BT_PICASSO,
	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
};

static const struct zorrocl zcl_spectrum = {
	.type		= BT_SPECTRUM,
	.ramid		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
};

static const struct zorrocl zcl_picasso4_z3 = {
	.type		= BT_PICASSO4,
	.regoffset	= 0x00600000,
	.ramsize	= 4 * MB_,
	.ramoffset	= 0x01000000,	/* 0x02000000 for 64 MiB boards */
};

static const struct zorrocl zcl_picasso4_z2 = {
	.type		= BT_PICASSO4,
	.regoffset	= 0x10000,
	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
	.ramid2		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2,
};


static const struct zorro_device_id cirrusfb_zorro_table[] = {
	{
		.id		= ZORRO_PROD_HELFRICH_SD64_REG,
		.driver_data	= (unsigned long)&zcl_sd64,
	}, {
		.id		= ZORRO_PROD_HELFRICH_PICCOLO_REG,
		.driver_data	= (unsigned long)&zcl_piccolo,
	}, {
		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
		.driver_data	= (unsigned long)&zcl_picasso,
	}, {
		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
		.driver_data	= (unsigned long)&zcl_spectrum,
	}, {
		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
		.driver_data	= (unsigned long)&zcl_picasso4_z3,
	}, {
		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG,
		.driver_data	= (unsigned long)&zcl_picasso4_z2,
	},
	{ 0 }
};
MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
#endif /* CONFIG_ZORRO */

#ifdef CIRRUSFB_DEBUG
enum cirrusfb_dbg_reg_class {
	CRT,
	SEQ
};
#endif		/* CIRRUSFB_DEBUG */

/* info about board */
struct cirrusfb_info {};

static bool noaccel;
static char *mode_option =;

/****************************************************************************/
/**** BEGIN PROTOTYPES ******************************************************/

/*--- Interface used by the world ------------------------------------------*/
static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
				struct fb_info *info);

/*--- Internal routines ----------------------------------------------------*/
static void init_vgachip(struct fb_info *info);
static void switch_monitor(struct cirrusfb_info *cinfo, int on);
static void WGen(const struct cirrusfb_info *cinfo,
		 int regnum, unsigned char val);
static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
static void AttrOn(const struct cirrusfb_info *cinfo);
static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
static void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
		  unsigned char red, unsigned char green, unsigned char blue);
#if 0
static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
		  unsigned char *red, unsigned char *green,
		  unsigned char *blue);
#endif
static void cirrusfb_WaitBLT(u8 __iomem *regbase);
static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
			    u_short curx, u_short cury,
			    u_short destx, u_short desty,
			    u_short width, u_short height,
			    u_short line_length);
static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
			      u_short x, u_short y,
			      u_short width, u_short height,
			      u32 fg_color, u32 bg_color,
			      u_short line_length, u_char blitmode);

static void bestclock(long freq, int *nom, int *den, int *div);

#ifdef CIRRUSFB_DEBUG
static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
static void cirrusfb_dbg_print_regs(struct fb_info *info,
				    caddr_t regbase,
				    enum cirrusfb_dbg_reg_class reg_class, ...);
#endif /* CIRRUSFB_DEBUG */

/*** END   PROTOTYPES ********************************************************/
/*****************************************************************************/
/*** BEGIN Interface Used by the World ***************************************/

static inline int is_laguna(const struct cirrusfb_info *cinfo)
{}

static int opencount;

/*--- Open /dev/fbx ---------------------------------------------------------*/
static int cirrusfb_open(struct fb_info *info, int user)
{}

/*--- Close /dev/fbx --------------------------------------------------------*/
static int cirrusfb_release(struct fb_info *info, int user)
{}

/**** END   Interface used by the World *************************************/
/****************************************************************************/
/**** BEGIN Hardware specific Routines **************************************/

/* Check if the MCLK is not a better clock source */
static int cirrusfb_check_mclk(struct fb_info *info, long freq)
{}

static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
				   struct fb_info *info)
{}

static int cirrusfb_check_var(struct fb_var_screeninfo *var,
			      struct fb_info *info)
{}

static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
{}

/*************************************************************************
	cirrusfb_set_par_foo()

	actually writes the values for a new video mode into the hardware,
**************************************************************************/
static int cirrusfb_set_par_foo(struct fb_info *info)
{}

/* for some reason incomprehensible to me, cirrusfb requires that you write
 * the registers twice for the settings to take..grr. -dte */
static int cirrusfb_set_par(struct fb_info *info)
{}

static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
			      unsigned blue, unsigned transp,
			      struct fb_info *info)
{}

/*************************************************************************
	cirrusfb_pan_display()

	performs display panning - provided hardware permits this
**************************************************************************/
static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
				struct fb_info *info)
{}

static int cirrusfb_blank(int blank_mode, struct fb_info *info)
{}

/**** END   Hardware specific Routines **************************************/
/****************************************************************************/
/**** BEGIN Internal Routines ***********************************************/

static void init_vgachip(struct fb_info *info)
{}

static void switch_monitor(struct cirrusfb_info *cinfo, int on)
{}

/******************************************/
/* Linux 2.6-style  accelerated functions */
/******************************************/

static int cirrusfb_sync(struct fb_info *info)
{}

static void cirrusfb_fillrect(struct fb_info *info,
			      const struct fb_fillrect *region)
{}

static void cirrusfb_copyarea(struct fb_info *info,
			      const struct fb_copyarea *area)
{}

static void cirrusfb_imageblit(struct fb_info *info,
			       const struct fb_image *image)
{}

#ifdef CONFIG_PCI
static int release_io_ports;

/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
 * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
 * seem to have. */
static unsigned int cirrusfb_get_memsize(struct fb_info *info,
					 u8 __iomem *regbase)
{}

static void get_pci_addrs(const struct pci_dev *pdev,
			  unsigned long *display, unsigned long *registers)
{}

static void cirrusfb_pci_unmap(struct fb_info *info)
{}
#endif /* CONFIG_PCI */

#ifdef CONFIG_ZORRO
static void cirrusfb_zorro_unmap(struct fb_info *info)
{
	struct cirrusfb_info *cinfo = info->par;
	struct zorro_dev *zdev = to_zorro_dev(info->device);

	if (info->fix.smem_start > 16 * MB_)
		iounmap(info->screen_base);
	if (info->fix.mmio_start > 16 * MB_)
		iounmap(cinfo->regbase);

	zorro_release_device(zdev);
}
#endif /* CONFIG_ZORRO */

/* function table of the above functions */
static const struct fb_ops cirrusfb_ops =;

static int cirrusfb_set_fbinfo(struct fb_info *info)
{}

static int cirrusfb_register(struct fb_info *info)
{}

static void cirrusfb_cleanup(struct fb_info *info)
{}

#ifdef CONFIG_PCI
static int cirrusfb_pci_register(struct pci_dev *pdev,
				 const struct pci_device_id *ent)
{}

static void cirrusfb_pci_unregister(struct pci_dev *pdev)
{}

static struct pci_driver cirrusfb_pci_driver =;
#endif /* CONFIG_PCI */

#ifdef CONFIG_ZORRO
static int cirrusfb_zorro_register(struct zorro_dev *z,
				   const struct zorro_device_id *ent)
{
	struct fb_info *info;
	int error;
	const struct zorrocl *zcl;
	enum cirrus_board btype;
	unsigned long regbase, ramsize, rambase;
	struct cirrusfb_info *cinfo;

	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
	if (!info)
		return -ENOMEM;

	zcl = (const struct zorrocl *)ent->driver_data;
	btype = zcl->type;
	regbase = zorro_resource_start(z) + zcl->regoffset;
	ramsize = zcl->ramsize;
	if (ramsize) {
		rambase = zorro_resource_start(z) + zcl->ramoffset;
		if (zorro_resource_len(z) == 64 * MB_) {
			/* Quirk for 64 MiB Picasso IV */
			rambase += zcl->ramoffset;
		}
	} else {
		struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
		if (!ram || !zorro_resource_len(ram)) {
			dev_err(info->device, "No video RAM found\n");
			error = -ENODEV;
			goto err_release_fb;
		}
		rambase = zorro_resource_start(ram);
		ramsize = zorro_resource_len(ram);
		if (zcl->ramid2 &&
		    (ram = zorro_find_device(zcl->ramid2, NULL))) {
			if (zorro_resource_start(ram) != rambase + ramsize) {
				dev_warn(info->device,
					 "Skipping non-contiguous RAM at %pR\n",
					 &ram->resource);
			} else {
				ramsize += zorro_resource_len(ram);
			}
		}
	}

	dev_info(info->device,
		 "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n",
		 cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
		 rambase);

	if (!zorro_request_device(z, "cirrusfb")) {
		dev_err(info->device, "Cannot reserve %pR\n", &z->resource);
		error = -EBUSY;
		goto err_release_fb;
	}

	cinfo = info->par;
	cinfo->btype = btype;

	info->fix.mmio_start = regbase;
	cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
					    : ZTWO_VADDR(regbase);
	if (!cinfo->regbase) {
		dev_err(info->device, "Cannot map registers\n");
		error = -EIO;
		goto err_release_dev;
	}

	info->fix.smem_start = rambase;
	info->screen_size = ramsize;
	info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
					       : ZTWO_VADDR(rambase);
	if (!info->screen_base) {
		dev_err(info->device, "Cannot map video RAM\n");
		error = -EIO;
		goto err_unmap_reg;
	}

	cinfo->unmap = cirrusfb_zorro_unmap;

	dev_info(info->device,
		 "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n",
		 ramsize / MB_, rambase);

	/* MCLK select etc. */
	if (cirrusfb_board_info[btype].init_sr1f)
		vga_wseq(cinfo->regbase, CL_SEQR1F,
			 cirrusfb_board_info[btype].sr1f);

	error = cirrusfb_register(info);
	if (error) {
		dev_err(info->device, "Failed to register device, error %d\n",
			error);
		goto err_unmap_ram;
	}

	zorro_set_drvdata(z, info);
	return 0;

err_unmap_ram:
	if (rambase > 16 * MB_)
		iounmap(info->screen_base);

err_unmap_reg:
	if (regbase > 16 * MB_)
		iounmap(cinfo->regbase);
err_release_dev:
	zorro_release_device(z);
err_release_fb:
	framebuffer_release(info);
	return error;
}

static void cirrusfb_zorro_unregister(struct zorro_dev *z)
{
	struct fb_info *info = zorro_get_drvdata(z);

	cirrusfb_cleanup(info);
	zorro_set_drvdata(z, NULL);
}

static struct zorro_driver cirrusfb_zorro_driver = {
	.name		= "cirrusfb",
	.id_table	= cirrusfb_zorro_table,
	.probe		= cirrusfb_zorro_register,
	.remove		= cirrusfb_zorro_unregister,
};
#endif /* CONFIG_ZORRO */

#ifndef MODULE
static int __init cirrusfb_setup(char *options)
{}
#endif

    /*
     *  Modularization
     */

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

static int __init cirrusfb_init(void)
{}

static void __exit cirrusfb_exit(void)
{}

module_init();

module_param(mode_option, charp, 0);
MODULE_PARM_DESC();
module_param(noaccel, bool, 0);
MODULE_PARM_DESC();

#ifdef MODULE
module_exit(cirrusfb_exit);
#endif

/**********************************************************************/
/* about the following functions - I have used the same names for the */
/* functions as Markus Wild did in his Retina driver for NetBSD as    */
/* they just made sense for this purpose. Apart from that, I wrote    */
/* these functions myself.					    */
/**********************************************************************/

/*** WGen() - write into one of the external/general registers ***/
static void WGen(const struct cirrusfb_info *cinfo,
		  int regnum, unsigned char val)
{}

/*** RGen() - read out one of the external/general registers ***/
static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
{}

/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
static void AttrOn(const struct cirrusfb_info *cinfo)
{}

/*** WHDR() - write into the Hidden DAC register ***/
/* as the HDR is the only extension register that requires special treatment
 * (the other extension registers are accessible just like the "ordinary"
 * registers of their functional group) here is a specialized routine for
 * accessing the HDR
 */
static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
{}

/*** WSFR() - write to the "special function register" (SFR) ***/
static void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
{}

/* The Picasso has a second register for switching the monitor bit */
static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
{}

/*** WClut - set CLUT entry (range: 0..63) ***/
static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
	    unsigned char green, unsigned char blue)
{}

#if 0
/*** RClut - read CLUT entry (range 0..63) ***/
static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
	    unsigned char *green, unsigned char *blue)
{
	unsigned int data = VGA_PEL_D;

	vga_w(cinfo->regbase, VGA_PEL_IR, regnum);

	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
		if (cinfo->btype == BT_PICASSO)
			data += 0xfff;
		*red = vga_r(cinfo->regbase, data);
		*green = vga_r(cinfo->regbase, data);
		*blue = vga_r(cinfo->regbase, data);
	} else {
		*blue = vga_r(cinfo->regbase, data);
		*green = vga_r(cinfo->regbase, data);
		*red = vga_r(cinfo->regbase, data);
	}
}
#endif

/*******************************************************************
	cirrusfb_WaitBLT()

	Wait for the BitBLT engine to complete a possible earlier job
*********************************************************************/

/* FIXME: use interrupts instead */
static void cirrusfb_WaitBLT(u8 __iomem *regbase)
{}

/*******************************************************************
	cirrusfb_BitBLT()

	perform accelerated "scrolling"
********************************************************************/

static void cirrusfb_set_blitter(u8 __iomem *regbase,
			    u_short nwidth, u_short nheight,
			    u_long nsrc, u_long ndest,
			    u_short bltmode, u_short line_length)

{}

/*******************************************************************
	cirrusfb_BitBLT()

	perform accelerated "scrolling"
********************************************************************/

static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
			    u_short curx, u_short cury,
			    u_short destx, u_short desty,
			    u_short width, u_short height,
			    u_short line_length)
{}

/*******************************************************************
	cirrusfb_RectFill()

	perform accelerated rectangle fill
********************************************************************/

static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
		     u_short x, u_short y, u_short width, u_short height,
		     u32 fg_color, u32 bg_color, u_short line_length,
		     u_char blitmode)
{}

/**************************************************************************
 * bestclock() - determine closest possible clock lower(?) than the
 * desired pixel clock
 **************************************************************************/
static void bestclock(long freq, int *nom, int *den, int *div)
{}

/* -------------------------------------------------------------------------
 *
 * debugging functions
 *
 * -------------------------------------------------------------------------
 */

#ifdef CIRRUSFB_DEBUG

/*
 * cirrusfb_dbg_print_regs
 * @regbase: If using newmmio, the newmmio base address, otherwise %NULL
 * @reg_class: type of registers to read: %CRT, or %SEQ
 *
 * DESCRIPTION:
 * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
 * old-style I/O ports are queried for information, otherwise MMIO is
 * used at the given @base address to query the information.
 */

static void cirrusfb_dbg_print_regs(struct fb_info *info,
				    caddr_t regbase,
				    enum cirrusfb_dbg_reg_class reg_class, ...)
{
	va_list list;
	unsigned char val = 0;
	unsigned reg;
	char *name;

	va_start(list, reg_class);

	name = va_arg(list, char *);
	while (name != NULL) {
		reg = va_arg(list, int);

		switch (reg_class) {
		case CRT:
			val = vga_rcrt(regbase, (unsigned char) reg);
			break;
		case SEQ:
			val = vga_rseq(regbase, (unsigned char) reg);
			break;
		default:
			/* should never occur */
			assert(false);
			break;
		}

		dev_dbg(info->device, "%8s = 0x%02X\n", name, val);

		name = va_arg(list, char *);
	}

	va_end(list);
}

/*
 * cirrusfb_dbg_reg_dump
 * @base: If using newmmio, the newmmio base address, otherwise %NULL
 *
 * DESCRIPTION:
 * Dumps a list of interesting VGA and CIRRUSFB registers.  If @base is %NULL,
 * old-style I/O ports are queried for information, otherwise MMIO is
 * used at the given @base address to query the information.
 */

static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
{
	dev_dbg(info->device, "VGA CRTC register dump:\n");

	cirrusfb_dbg_print_regs(info, regbase, CRT,
			   "CR00", 0x00,
			   "CR01", 0x01,
			   "CR02", 0x02,
			   "CR03", 0x03,
			   "CR04", 0x04,
			   "CR05", 0x05,
			   "CR06", 0x06,
			   "CR07", 0x07,
			   "CR08", 0x08,
			   "CR09", 0x09,
			   "CR0A", 0x0A,
			   "CR0B", 0x0B,
			   "CR0C", 0x0C,
			   "CR0D", 0x0D,
			   "CR0E", 0x0E,
			   "CR0F", 0x0F,
			   "CR10", 0x10,
			   "CR11", 0x11,
			   "CR12", 0x12,
			   "CR13", 0x13,
			   "CR14", 0x14,
			   "CR15", 0x15,
			   "CR16", 0x16,
			   "CR17", 0x17,
			   "CR18", 0x18,
			   "CR22", 0x22,
			   "CR24", 0x24,
			   "CR26", 0x26,
			   "CR2D", 0x2D,
			   "CR2E", 0x2E,
			   "CR2F", 0x2F,
			   "CR30", 0x30,
			   "CR31", 0x31,
			   "CR32", 0x32,
			   "CR33", 0x33,
			   "CR34", 0x34,
			   "CR35", 0x35,
			   "CR36", 0x36,
			   "CR37", 0x37,
			   "CR38", 0x38,
			   "CR39", 0x39,
			   "CR3A", 0x3A,
			   "CR3B", 0x3B,
			   "CR3C", 0x3C,
			   "CR3D", 0x3D,
			   "CR3E", 0x3E,
			   "CR3F", 0x3F,
			   NULL);

	dev_dbg(info->device, "\n");

	dev_dbg(info->device, "VGA SEQ register dump:\n");

	cirrusfb_dbg_print_regs(info, regbase, SEQ,
			   "SR00", 0x00,
			   "SR01", 0x01,
			   "SR02", 0x02,
			   "SR03", 0x03,
			   "SR04", 0x04,
			   "SR08", 0x08,
			   "SR09", 0x09,
			   "SR0A", 0x0A,
			   "SR0B", 0x0B,
			   "SR0D", 0x0D,
			   "SR10", 0x10,
			   "SR11", 0x11,
			   "SR12", 0x12,
			   "SR13", 0x13,
			   "SR14", 0x14,
			   "SR15", 0x15,
			   "SR16", 0x16,
			   "SR17", 0x17,
			   "SR18", 0x18,
			   "SR19", 0x19,
			   "SR1A", 0x1A,
			   "SR1B", 0x1B,
			   "SR1C", 0x1C,
			   "SR1D", 0x1D,
			   "SR1E", 0x1E,
			   "SR1F", 0x1F,
			   NULL);

	dev_dbg(info->device, "\n");
}

#endif				/* CIRRUSFB_DEBUG */