cirrusfb.c 89.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/*
 * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
 *
 * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
 *
 * 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.
 *
 */

#define CIRRUSFB_VERSION "2.0-pre2"

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/selection.h>
#include <asm/pgtable.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
#ifdef CONFIG_PPC_PREP
61
#include <asm/machdep.h>
K
Krzysztof Helt 已提交
62
#define isPReP machine_is(prep)
L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
#else
#define isPReP 0
#endif

#include "video/vga.h"
#include "video/cirrus.h"

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

/* enable debug output? */
/* #define CIRRUSFB_DEBUG 1 */

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

/* debug output */
#ifdef CIRRUSFB_DEBUG
K
Krzysztof Helt 已提交
84 85
#define DPRINTK(fmt, args...) \
	printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
L
Linus Torvalds 已提交
86 87 88 89 90 91 92
#else
#define DPRINTK(fmt, args...)
#endif

/* debugging assertions */
#ifndef CIRRUSFB_NDEBUG
#define assert(expr) \
K
Krzysztof Helt 已提交
93 94 95 96
	if (!(expr)) { \
		printk("Assertion failed! %s,%s,%s,line=%d\n", \
		#expr, __FILE__, __FUNCTION__, __LINE__); \
	}
L
Linus Torvalds 已提交
97 98 99 100
#else
#define assert(expr)
#endif

K
Krzysztof Helt 已提交
101
#define MB_ (1024 * 1024)
L
Linus Torvalds 已提交
102 103 104 105 106 107 108 109 110 111 112
#define KB_ (1024)

#define MAX_NUM_BOARDS 7

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

/* board types */
K
Krzysztof Helt 已提交
113
enum cirrus_board {
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122
	BT_NONE = 0,
	BT_SD64,
	BT_PICCOLO,
	BT_PICASSO,
	BT_SPECTRUM,
	BT_PICASSO4,	/* GD5446 */
	BT_ALPINE,	/* GD543x/4x */
	BT_GD5480,
	BT_LAGUNA,	/* GD546x */
K
Krzysztof Helt 已提交
123
};
L
Linus Torvalds 已提交
124 125 126 127

/*
 * per-board-type information, used for enumerating and abstracting
 * chip-specific information
K
Krzysztof Helt 已提交
128
 * NOTE: MUST be in the same order as enum cirrus_board in order to
L
Linus Torvalds 已提交
129 130 131 132 133 134 135 136 137
 * 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 {
	char *name;		/* ASCII name of chipset */
	long maxclock[5];		/* maximum video clock */
	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
138 139
	bool init_sr07 : 1; /* init SR07 during init_vgachip() */
	bool init_sr1f : 1; /* write SR1F during init_vgachip() */
K
Krzysztof Helt 已提交
140 141
	/* construct bit 19 of screen start address */
	bool scrn_start_bit19 : 1;
L
Linus Torvalds 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

	/* initial SR07 value, then for each mode */
	unsigned char sr07;
	unsigned char sr07_1bpp;
	unsigned char sr07_1bpp_mux;
	unsigned char sr07_8bpp;
	unsigned char sr07_8bpp_mux;

	unsigned char sr1f;	/* SR1F VGA initial register value */
} cirrusfb_board_info[] = {
	[BT_SD64] = {
		.name			= "CL SD64",
		.maxclock		= {
			/* guess */
			/* the SD64/P4 have a higher max. videoclock */
			140000, 140000, 140000, 140000, 140000,
		},
159 160 161
		.init_sr07		= true,
		.init_sr1f		= true,
		.scrn_start_bit19	= true,
L
Linus Torvalds 已提交
162 163 164 165 166 167 168 169 170 171 172
		.sr07			= 0xF0,
		.sr07_1bpp		= 0xF0,
		.sr07_8bpp		= 0xF1,
		.sr1f			= 0x20
	},
	[BT_PICCOLO] = {
		.name			= "CL Piccolo",
		.maxclock		= {
			/* guess */
			90000, 90000, 90000, 90000, 90000
		},
173 174 175
		.init_sr07		= true,
		.init_sr1f		= true,
		.scrn_start_bit19	= false,
L
Linus Torvalds 已提交
176 177 178 179 180 181 182 183 184 185 186
		.sr07			= 0x80,
		.sr07_1bpp		= 0x80,
		.sr07_8bpp		= 0x81,
		.sr1f			= 0x22
	},
	[BT_PICASSO] = {
		.name			= "CL Picasso",
		.maxclock		= {
			/* guess */
			90000, 90000, 90000, 90000, 90000
		},
187 188 189
		.init_sr07		= true,
		.init_sr1f		= true,
		.scrn_start_bit19	= false,
L
Linus Torvalds 已提交
190 191 192 193 194 195 196 197 198 199 200
		.sr07			= 0x20,
		.sr07_1bpp		= 0x20,
		.sr07_8bpp		= 0x21,
		.sr1f			= 0x22
	},
	[BT_SPECTRUM] = {
		.name			= "CL Spectrum",
		.maxclock		= {
			/* guess */
			90000, 90000, 90000, 90000, 90000
		},
201 202 203
		.init_sr07		= true,
		.init_sr1f		= true,
		.scrn_start_bit19	= false,
L
Linus Torvalds 已提交
204 205 206 207 208 209 210 211 212 213
		.sr07			= 0x80,
		.sr07_1bpp		= 0x80,
		.sr07_8bpp		= 0x81,
		.sr1f			= 0x22
	},
	[BT_PICASSO4] = {
		.name			= "CL Picasso4",
		.maxclock		= {
			135100, 135100, 85500, 85500, 0
		},
214 215 216
		.init_sr07		= true,
		.init_sr1f		= false,
		.scrn_start_bit19	= true,
L
Linus Torvalds 已提交
217 218 219 220 221 222 223 224 225 226 227
		.sr07			= 0x20,
		.sr07_1bpp		= 0x20,
		.sr07_8bpp		= 0x21,
		.sr1f			= 0
	},
	[BT_ALPINE] = {
		.name			= "CL Alpine",
		.maxclock		= {
			/* for the GD5430.  GD5446 can do more... */
			85500, 85500, 50000, 28500, 0
		},
228 229 230
		.init_sr07		= true,
		.init_sr1f		= true,
		.scrn_start_bit19	= true,
L
Linus Torvalds 已提交
231 232 233 234 235 236 237 238 239 240 241 242
		.sr07			= 0xA0,
		.sr07_1bpp		= 0xA1,
		.sr07_1bpp_mux		= 0xA7,
		.sr07_8bpp		= 0xA1,
		.sr07_8bpp_mux		= 0xA7,
		.sr1f			= 0x1C
	},
	[BT_GD5480] = {
		.name			= "CL GD5480",
		.maxclock		= {
			135100, 200000, 200000, 135100, 135100
		},
243 244 245
		.init_sr07		= true,
		.init_sr1f		= true,
		.scrn_start_bit19	= true,
L
Linus Torvalds 已提交
246 247 248 249 250 251 252 253 254 255 256
		.sr07			= 0x10,
		.sr07_1bpp		= 0x11,
		.sr07_8bpp		= 0x11,
		.sr1f			= 0x1C
	},
	[BT_LAGUNA] = {
		.name			= "CL Laguna",
		.maxclock		= {
			/* guess */
			135100, 135100, 135100, 135100, 135100,
		},
257 258 259
		.init_sr07		= false,
		.init_sr1f		= false,
		.scrn_start_bit19	= true,
L
Linus Torvalds 已提交
260 261 262 263 264
	}
};

#ifdef CONFIG_PCI
#define CHIP(id, btype) \
265
	{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
L
Linus Torvalds 已提交
266 267

static struct pci_device_id cirrusfb_pci_table[] = {
K
Krzysztof Helt 已提交
268 269 270 271 272 273 274 275 276 277 278
	CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
	CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE),
	CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE),
	CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
	CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
	CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
	CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
	CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
	CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
	CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
	CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/
L
Linus Torvalds 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
	{ 0, }
};
MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
#undef CHIP
#endif /* CONFIG_PCI */

#ifdef CONFIG_ZORRO
static const struct zorro_device_id cirrusfb_zorro_table[] = {
	{
		.id		= ZORRO_PROD_HELFRICH_SD64_RAM,
		.driver_data	= BT_SD64,
	}, {
		.id		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
		.driver_data	= BT_PICCOLO,
	}, {
K
Krzysztof Helt 已提交
294
		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
L
Linus Torvalds 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
		.driver_data	= BT_PICASSO,
	}, {
		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
		.driver_data	= BT_SPECTRUM,
	}, {
		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
		.driver_data	= BT_PICASSO4,
	},
	{ 0 }
};

static const struct {
	zorro_id id2;
	unsigned long size;
} cirrusfb_zorro_table2[] = {
	[BT_SD64] = {
		.id2	= ZORRO_PROD_HELFRICH_SD64_REG,
		.size	= 0x400000
	},
	[BT_PICCOLO] = {
		.id2	= ZORRO_PROD_HELFRICH_PICCOLO_REG,
		.size	= 0x200000
	},
	[BT_PICASSO] = {
		.id2	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
		.size	= 0x200000
	},
	[BT_SPECTRUM] = {
		.id2	= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
		.size	= 0x200000
	},
	[BT_PICASSO4] = {
		.id2	= 0,
		.size	= 0x400000
	}
};
#endif /* CONFIG_ZORRO */

struct cirrusfb_regs {
	__u32 line_length;	/* in BYTES! */
	__u32 visual;
	__u32 type;

	long freq;
	long nom;
	long den;
	long div;
	long multiplexing;
	long mclk;
	long divMCLK;

	long HorizRes;		/* The x resolution in pixel */
	long HorizTotal;
	long HorizDispEnd;
	long HorizBlankStart;
	long HorizBlankEnd;
	long HorizSyncStart;
	long HorizSyncEnd;

	long VertRes;		/* the physical y resolution in scanlines */
	long VertTotal;
	long VertDispEnd;
	long VertSyncStart;
	long VertSyncEnd;
	long VertBlankStart;
	long VertBlankEnd;
};

#ifdef CIRRUSFB_DEBUG
K
Krzysztof Helt 已提交
364
enum cirrusfb_dbg_reg_class {
K
Krzysztof Helt 已提交
365 366
	CRT,
	SEQ
K
Krzysztof Helt 已提交
367
};
K
Krzysztof Helt 已提交
368
#endif		/* CIRRUSFB_DEBUG */
L
Linus Torvalds 已提交
369 370 371 372 373 374 375 376 377

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

	u8 __iomem *fbmem;
	u8 __iomem *regbase;
	u8 __iomem *mem;
	unsigned long size;
K
Krzysztof Helt 已提交
378
	enum cirrus_board btype;
L
Linus Torvalds 已提交
379 380 381 382 383 384 385 386
	unsigned char SFR;	/* Shadow of special function register */

	unsigned long fbmem_phys;
	unsigned long fbregs_phys;

	struct cirrusfb_regs currentmode;
	int blank_mode;

387
	u32	pseudo_palette[16];
L
Linus Torvalds 已提交
388 389 390 391 392 393 394 395 396 397 398 399
	struct { u8 red, green, blue, pad; } palette[256];

#ifdef CONFIG_ZORRO
	struct zorro_dev *zdev;
#endif
#ifdef CONFIG_PCI
	struct pci_dev *pdev;
#endif
	void (*unmap)(struct cirrusfb_info *cinfo);
};

static unsigned cirrusfb_def_mode = 1;
K
Krzysztof Helt 已提交
400
static int noaccel;
L
Linus Torvalds 已提交
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

/*
 *    Predefined Video Modes
 */

static const struct {
	const char *name;
	struct fb_var_screeninfo var;
} cirrusfb_predefined[] = {
	{
		/* autodetect mode */
		.name	= "Autodetect",
	}, {
		/* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
		.name	= "640x480",
		.var	= {
			.xres		= 640,
			.yres		= 480,
			.xres_virtual	= 640,
			.yres_virtual	= 480,
			.bits_per_pixel	= 8,
			.red		= { .length = 8 },
			.green		= { .length = 8 },
			.blue		= { .length = 8 },
			.width		= -1,
			.height		= -1,
			.pixclock	= 40000,
			.left_margin	= 48,
			.right_margin	= 16,
			.upper_margin	= 32,
			.lower_margin	= 8,
			.hsync_len	= 96,
			.vsync_len	= 4,
K
Krzysztof Helt 已提交
434
			.sync	= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
L
Linus Torvalds 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
			.vmode		= FB_VMODE_NONINTERLACED
		 }
	}, {
		/* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
		.name	= "800x600",
		.var	= {
			.xres		= 800,
			.yres		= 600,
			.xres_virtual	= 800,
			.yres_virtual	= 600,
			.bits_per_pixel	= 8,
			.red		= { .length = 8 },
			.green		= { .length = 8 },
			.blue		= { .length = 8 },
			.width		= -1,
			.height		= -1,
			.pixclock	= 20000,
			.left_margin	= 128,
			.right_margin	= 16,
			.upper_margin	= 24,
			.lower_margin	= 2,
			.hsync_len	= 96,
			.vsync_len	= 6,
			.vmode		= FB_VMODE_NONINTERLACED
		 }
	}, {
		/*
		 * Modeline from XF86Config:
		 * Mode "1024x768" 80  1024 1136 1340 1432  768 770 774 805
		 */
		/* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
		.name	= "1024x768",
		.var	= {
			.xres		= 1024,
			.yres		= 768,
			.xres_virtual	= 1024,
			.yres_virtual	= 768,
			.bits_per_pixel	= 8,
			.red		= { .length = 8 },
			.green		= { .length = 8 },
			.blue		= { .length = 8 },
			.width		= -1,
			.height		= -1,
			.pixclock	= 12500,
			.left_margin	= 144,
			.right_margin	= 32,
			.upper_margin	= 30,
			.lower_margin	= 2,
			.hsync_len	= 192,
			.vsync_len	= 6,
			.vmode		= FB_VMODE_NONINTERLACED
		}
	}
};

#define NUM_TOTAL_MODES    ARRAY_SIZE(cirrusfb_predefined)

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

/*--- Interface used by the world ------------------------------------------*/
K
Krzysztof Helt 已提交
496
static int cirrusfb_init(void);
L
Linus Torvalds 已提交
497
#ifndef MODULE
K
Krzysztof Helt 已提交
498
static int cirrusfb_setup(char *options);
L
Linus Torvalds 已提交
499 500
#endif

K
Krzysztof Helt 已提交
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517
static int cirrusfb_open(struct fb_info *info, int user);
static int cirrusfb_release(struct fb_info *info, int user);
static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
			      unsigned blue, unsigned transp,
			      struct fb_info *info);
static int cirrusfb_check_var(struct fb_var_screeninfo *var,
			      struct fb_info *info);
static int cirrusfb_set_par(struct fb_info *info);
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);
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);
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

/* function table of the above functions */
static struct fb_ops cirrusfb_ops = {
	.owner		= THIS_MODULE,
	.fb_open	= cirrusfb_open,
	.fb_release	= cirrusfb_release,
	.fb_setcolreg	= cirrusfb_setcolreg,
	.fb_check_var	= cirrusfb_check_var,
	.fb_set_par	= cirrusfb_set_par,
	.fb_pan_display = cirrusfb_pan_display,
	.fb_blank	= cirrusfb_blank,
	.fb_fillrect	= cirrusfb_fillrect,
	.fb_copyarea	= cirrusfb_copyarea,
	.fb_imageblit	= cirrusfb_imageblit,
};

/*--- Hardware Specific Routines -------------------------------------------*/
K
Krzysztof Helt 已提交
535
static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
L
Linus Torvalds 已提交
536 537 538
				struct cirrusfb_regs *regs,
				const struct fb_info *info);
/*--- Internal routines ----------------------------------------------------*/
K
Krzysztof Helt 已提交
539 540 541 542 543 544 545 546 547 548 549
static void init_vgachip(struct cirrusfb_info *cinfo);
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);
L
Linus Torvalds 已提交
550
#if 0
K
Krzysztof Helt 已提交
551 552 553
static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
		  unsigned char *red, unsigned char *green,
		  unsigned char *blue);
L
Linus Torvalds 已提交
554
#endif
K
Krzysztof Helt 已提交
555 556 557 558 559 560 561 562 563 564 565 566 567 568
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,
			      u_char color, u_short line_length);

static void bestclock(long freq, long *best,
		      long *nom, long *den,
		      long *div, long maxfreq);
L
Linus Torvalds 已提交
569 570

#ifdef CIRRUSFB_DEBUG
K
Krzysztof Helt 已提交
571 572 573
static void cirrusfb_dump(void);
static void cirrusfb_dbg_reg_dump(caddr_t regbase);
static void cirrusfb_dbg_print_regs(caddr_t regbase,
K
Krzysztof Helt 已提交
574
				    enum cirrusfb_dbg_reg_class reg_class, ...);
K
Krzysztof Helt 已提交
575
static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);
L
Linus Torvalds 已提交
576 577 578 579 580 581
#endif /* CIRRUSFB_DEBUG */

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

K
Krzysztof Helt 已提交
582
static int opencount;
L
Linus Torvalds 已提交
583 584

/*--- Open /dev/fbx ---------------------------------------------------------*/
K
Krzysztof Helt 已提交
585
static int cirrusfb_open(struct fb_info *info, int user)
L
Linus Torvalds 已提交
586 587
{
	if (opencount++ == 0)
K
Krzysztof Helt 已提交
588
		switch_monitor(info->par, 1);
L
Linus Torvalds 已提交
589 590 591 592
	return 0;
}

/*--- Close /dev/fbx --------------------------------------------------------*/
K
Krzysztof Helt 已提交
593
static int cirrusfb_release(struct fb_info *info, int user)
L
Linus Torvalds 已提交
594 595
{
	if (--opencount == 0)
K
Krzysztof Helt 已提交
596
		switch_monitor(info->par, 0);
L
Linus Torvalds 已提交
597 598 599 600 601 602 603 604
	return 0;
}

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

/* Get a good MCLK value */
K
Krzysztof Helt 已提交
605
static long cirrusfb_get_mclk(long freq, int bpp, long *div)
L
Linus Torvalds 已提交
606 607 608
{
	long mclk;

K
Krzysztof Helt 已提交
609
	assert(div != NULL);
L
Linus Torvalds 已提交
610 611 612 613 614 615 616 617 618

	/* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
	 * Assume a 64-bit data path for now.  The formula is:
	 * ((B * PCLK * 2)/W) * 1.2
	 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
	mclk = ((bpp / 8) * freq * 2) / 4;
	mclk = (mclk * 12) / 10;
	if (mclk < 50000)
		mclk = 50000;
K
Krzysztof Helt 已提交
619
	DPRINTK("Use MCLK of %ld kHz\n", mclk);
L
Linus Torvalds 已提交
620 621 622 623

	/* Calculate value for SR1F.  Multiply by 2 so we can round up. */
	mclk = ((mclk * 16) / 14318);
	mclk = (mclk + 1) / 2;
K
Krzysztof Helt 已提交
624
	DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk);
L
Linus Torvalds 已提交
625 626 627 628 629 630

	/* Determine if we should use MCLK instead of VCLK, and if so, what we
	   * should divide it by to get VCLK */
	switch (freq) {
	case 24751 ... 25249:
		*div = 2;
K
Krzysztof Helt 已提交
631
		DPRINTK("Using VCLK = MCLK/2\n");
L
Linus Torvalds 已提交
632 633 634
		break;
	case 49501 ... 50499:
		*div = 1;
K
Krzysztof Helt 已提交
635
		DPRINTK("Using VCLK = MCLK\n");
L
Linus Torvalds 已提交
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
		break;
	default:
		*div = 0;
		break;
	}

	return mclk;
}

static int cirrusfb_check_var(struct fb_var_screeninfo *var,
			      struct fb_info *info)
{
	struct cirrusfb_info *cinfo = info->par;
	int nom, den;		/* translyting from pixels->bytes */
	int yres, i;
	static struct { int xres, yres; } modes[] =
	{ { 1600, 1280 },
	  { 1280, 1024 },
	  { 1024, 768 },
	  { 800, 600 },
	  { 640, 480 },
	  { -1, -1 } };

	switch (var->bits_per_pixel) {
	case 0 ... 1:
		var->bits_per_pixel = 1;
		nom = 4;
		den = 8;
		break;		/* 8 pixel per byte, only 1/4th of mem usable */
	case 2 ... 8:
		var->bits_per_pixel = 8;
		nom = 1;
		den = 1;
		break;		/* 1 pixel == 1 byte */
	case 9 ... 16:
		var->bits_per_pixel = 16;
		nom = 2;
		den = 1;
		break;		/* 2 bytes per pixel */
	case 17 ... 24:
		var->bits_per_pixel = 24;
		nom = 3;
		den = 1;
		break;		/* 3 bytes per pixel */
	case 25 ... 32:
		var->bits_per_pixel = 32;
		nom = 4;
		den = 1;
		break;		/* 4 bytes per pixel */
	default:
K
Krzysztof Helt 已提交
686 687
		printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
			"color depth not supported.\n",
L
Linus Torvalds 已提交
688
			var->xres, var->yres, var->bits_per_pixel);
K
Krzysztof Helt 已提交
689
		DPRINTK("EXIT - EINVAL error\n");
L
Linus Torvalds 已提交
690 691 692 693
		return -EINVAL;
	}

	if (var->xres * nom / den * var->yres > cinfo->size) {
K
Krzysztof Helt 已提交
694 695
		printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
			"resolution too high to fit into video memory!\n",
L
Linus Torvalds 已提交
696
			var->xres, var->yres, var->bits_per_pixel);
K
Krzysztof Helt 已提交
697
		DPRINTK("EXIT - EINVAL error\n");
L
Linus Torvalds 已提交
698 699 700 701 702 703
		return -EINVAL;
	}

	/* use highest possible virtual resolution */
	if (var->xres_virtual == -1 &&
	    var->yres_virtual == -1) {
K
Krzysztof Helt 已提交
704 705
		printk(KERN_INFO
		     "cirrusfb: using maximum available virtual resolution\n");
L
Linus Torvalds 已提交
706 707 708 709 710
		for (i = 0; modes[i].xres != -1; i++) {
			if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2)
				break;
		}
		if (modes[i].xres == -1) {
K
Krzysztof Helt 已提交
711 712 713
			printk(KERN_ERR "cirrusfb: could not find a virtual "
				"resolution that fits into video memory!!\n");
			DPRINTK("EXIT - EINVAL error\n");
L
Linus Torvalds 已提交
714 715 716 717 718
			return -EINVAL;
		}
		var->xres_virtual = modes[i].xres;
		var->yres_virtual = modes[i].yres;

K
Krzysztof Helt 已提交
719 720 721
		printk(KERN_INFO "cirrusfb: virtual resolution set to "
			"maximum of %dx%d\n", var->xres_virtual,
			var->yres_virtual);
L
Linus Torvalds 已提交
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
	}

	if (var->xres_virtual < var->xres)
		var->xres_virtual = var->xres;
	if (var->yres_virtual < var->yres)
		var->yres_virtual = var->yres;

	if (var->xoffset < 0)
		var->xoffset = 0;
	if (var->yoffset < 0)
		var->yoffset = 0;

	/* truncate xoffset and yoffset to maximum if too high */
	if (var->xoffset > var->xres_virtual - var->xres)
		var->xoffset = var->xres_virtual - var->xres - 1;
	if (var->yoffset > var->yres_virtual - var->yres)
		var->yoffset = var->yres_virtual - var->yres - 1;

	switch (var->bits_per_pixel) {
	case 1:
		var->red.offset = 0;
		var->red.length = 1;
		var->green.offset = 0;
		var->green.length = 1;
		var->blue.offset = 0;
		var->blue.length = 1;
		break;

	case 8:
		var->red.offset = 0;
		var->red.length = 6;
		var->green.offset = 0;
		var->green.length = 6;
		var->blue.offset = 0;
		var->blue.length = 6;
		break;

	case 16:
K
Krzysztof Helt 已提交
760
		if (isPReP) {
L
Linus Torvalds 已提交
761 762 763 764 765 766 767 768 769 770 771 772 773 774
			var->red.offset = 2;
			var->green.offset = -3;
			var->blue.offset = 8;
		} else {
			var->red.offset = 10;
			var->green.offset = 5;
			var->blue.offset = 0;
		}
		var->red.length = 5;
		var->green.length = 5;
		var->blue.length = 5;
		break;

	case 24:
K
Krzysztof Helt 已提交
775
		if (isPReP) {
L
Linus Torvalds 已提交
776 777 778 779 780 781 782 783 784 785 786 787 788 789
			var->red.offset = 8;
			var->green.offset = 16;
			var->blue.offset = 24;
		} else {
			var->red.offset = 16;
			var->green.offset = 8;
			var->blue.offset = 0;
		}
		var->red.length = 8;
		var->green.length = 8;
		var->blue.length = 8;
		break;

	case 32:
K
Krzysztof Helt 已提交
790
		if (isPReP) {
L
Linus Torvalds 已提交
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
			var->red.offset = 8;
			var->green.offset = 16;
			var->blue.offset = 24;
		} else {
			var->red.offset = 16;
			var->green.offset = 8;
			var->blue.offset = 0;
		}
		var->red.length = 8;
		var->green.length = 8;
		var->blue.length = 8;
		break;

	default:
		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
806
		assert(false);
L
Linus Torvalds 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
		/* should never occur */
		break;
	}

	var->red.msb_right =
	    var->green.msb_right =
	    var->blue.msb_right =
	    var->transp.offset =
	    var->transp.length =
	    var->transp.msb_right = 0;

	yres = var->yres;
	if (var->vmode & FB_VMODE_DOUBLE)
		yres *= 2;
	else if (var->vmode & FB_VMODE_INTERLACED)
		yres = (yres + 1) / 2;

	if (yres >= 1280) {
K
Krzysztof Helt 已提交
825 826 827
		printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; "
			"special treatment required! (TODO)\n");
		DPRINTK("EXIT - EINVAL error\n");
L
Linus Torvalds 已提交
828 829 830 831 832 833
		return -EINVAL;
	}

	return 0;
}

K
Krzysztof Helt 已提交
834
static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
L
Linus Torvalds 已提交
835 836 837 838 839 840 841 842 843 844
				struct cirrusfb_regs *regs,
				const struct fb_info *info)
{
	long freq;
	long maxclock;
	int maxclockidx = 0;
	struct cirrusfb_info *cinfo = info->par;
	int xres, hfront, hsync, hback;
	int yres, vfront, vsync, vback;

K
Krzysztof Helt 已提交
845
	switch (var->bits_per_pixel) {
L
Linus Torvalds 已提交
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
	case 1:
		regs->line_length = var->xres_virtual / 8;
		regs->visual = FB_VISUAL_MONO10;
		maxclockidx = 0;
		break;

	case 8:
		regs->line_length = var->xres_virtual;
		regs->visual = FB_VISUAL_PSEUDOCOLOR;
		maxclockidx = 1;
		break;

	case 16:
		regs->line_length = var->xres_virtual * 2;
		regs->visual = FB_VISUAL_DIRECTCOLOR;
		maxclockidx = 2;
		break;

	case 24:
		regs->line_length = var->xres_virtual * 3;
		regs->visual = FB_VISUAL_DIRECTCOLOR;
		maxclockidx = 3;
		break;

	case 32:
		regs->line_length = var->xres_virtual * 4;
		regs->visual = FB_VISUAL_DIRECTCOLOR;
		maxclockidx = 4;
		break;

	default:
		DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
878
		assert(false);
L
Linus Torvalds 已提交
879 880 881 882 883 884 885 886 887
		/* should never occur */
		break;
	}

	regs->type = FB_TYPE_PACKED_PIXELS;

	/* convert from ps to kHz */
	freq = 1000000000 / var->pixclock;

K
Krzysztof Helt 已提交
888
	DPRINTK("desired pixclock: %ld kHz\n", freq);
L
Linus Torvalds 已提交
889 890 891 892 893 894 895 896 897 898 899 900 901 902

	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
	regs->multiplexing = 0;

	/* If the frequency is greater than we can support, we might be able
	 * to use multiplexing for the video mode */
	if (freq > maxclock) {
		switch (cinfo->btype) {
		case BT_ALPINE:
		case BT_GD5480:
			regs->multiplexing = 1;
			break;

		default:
K
Krzysztof Helt 已提交
903 904 905
			printk(KERN_ERR "cirrusfb: Frequency greater "
				"than maxclock (%ld kHz)\n", maxclock);
			DPRINTK("EXIT - return -EINVAL\n");
L
Linus Torvalds 已提交
906 907 908 909 910 911 912 913 914 915
			return -EINVAL;
		}
	}
#if 0
	/* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
	 * the VCLK is double the pixel clock. */
	switch (var->bits_per_pixel) {
	case 16:
	case 32:
		if (regs->HorizRes <= 800)
K
Krzysztof Helt 已提交
916 917
			/* Xbh has this type of clock for 32-bit */
			freq /= 2;
L
Linus Torvalds 已提交
918 919 920 921
		break;
	}
#endif

K
Krzysztof Helt 已提交
922 923 924 925
	bestclock(freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
		  maxclock);
	regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel,
					&regs->divMCLK);
L
Linus Torvalds 已提交
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951

	xres = var->xres;
	hfront = var->right_margin;
	hsync = var->hsync_len;
	hback = var->left_margin;

	yres = var->yres;
	vfront = var->lower_margin;
	vsync = var->vsync_len;
	vback = var->upper_margin;

	if (var->vmode & FB_VMODE_DOUBLE) {
		yres *= 2;
		vfront *= 2;
		vsync *= 2;
		vback *= 2;
	} else if (var->vmode & FB_VMODE_INTERLACED) {
		yres = (yres + 1) / 2;
		vfront = (vfront + 1) / 2;
		vsync = (vsync + 1) / 2;
		vback = (vback + 1) / 2;
	}
	regs->HorizRes = xres;
	regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
	regs->HorizDispEnd = xres / 8 - 1;
	regs->HorizBlankStart = xres / 8;
K
Krzysztof Helt 已提交
952 953
	/* does not count with "-5" */
	regs->HorizBlankEnd = regs->HorizTotal + 5;
L
Linus Torvalds 已提交
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
	regs->HorizSyncStart = (xres + hfront) / 8 + 1;
	regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;

	regs->VertRes = yres;
	regs->VertTotal = yres + vfront + vsync + vback - 2;
	regs->VertDispEnd = yres - 1;
	regs->VertBlankStart = yres;
	regs->VertBlankEnd = regs->VertTotal;
	regs->VertSyncStart = yres + vfront - 1;
	regs->VertSyncEnd = yres + vfront + vsync - 1;

	if (regs->VertRes >= 1024) {
		regs->VertTotal /= 2;
		regs->VertSyncStart /= 2;
		regs->VertSyncEnd /= 2;
		regs->VertDispEnd /= 2;
	}
	if (regs->multiplexing) {
		regs->HorizTotal /= 2;
		regs->HorizSyncStart /= 2;
		regs->HorizSyncEnd /= 2;
		regs->HorizDispEnd /= 2;
	}

	return 0;
}

K
Krzysztof Helt 已提交
981 982
static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val,
				int div)
L
Linus Torvalds 已提交
983
{
K
Krzysztof Helt 已提交
984
	assert(cinfo != NULL);
L
Linus Torvalds 已提交
985 986 987

	if (div == 2) {
		/* VCLK = MCLK/2 */
K
Krzysztof Helt 已提交
988 989 990
		unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
		vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1);
		vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
L
Linus Torvalds 已提交
991 992
	} else if (div == 1) {
		/* VCLK = MCLK */
K
Krzysztof Helt 已提交
993 994 995
		unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
		vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1);
		vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
L
Linus Torvalds 已提交
996
	} else {
K
Krzysztof Helt 已提交
997
		vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f);
L
Linus Torvalds 已提交
998 999 1000 1001 1002 1003 1004 1005
	}
}

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

	actually writes the values for a new video mode into the hardware,
**************************************************************************/
K
Krzysztof Helt 已提交
1006
static int cirrusfb_set_par_foo(struct fb_info *info)
L
Linus Torvalds 已提交
1007 1008 1009 1010 1011 1012 1013 1014 1015
{
	struct cirrusfb_info *cinfo = info->par;
	struct fb_var_screeninfo *var = &info->var;
	struct cirrusfb_regs regs;
	u8 __iomem *regbase = cinfo->regbase;
	unsigned char tmp;
	int offset = 0, err;
	const struct cirrusfb_board_info_rec *bi;

K
Krzysztof Helt 已提交
1016 1017
	DPRINTK("ENTER\n");
	DPRINTK("Requested mode: %dx%dx%d\n",
L
Linus Torvalds 已提交
1018
	       var->xres, var->yres, var->bits_per_pixel);
K
Krzysztof Helt 已提交
1019
	DPRINTK("pixclock: %d\n", var->pixclock);
L
Linus Torvalds 已提交
1020

K
Krzysztof Helt 已提交
1021
	init_vgachip(cinfo);
L
Linus Torvalds 已提交
1022 1023

	err = cirrusfb_decode_var(var, &regs, info);
K
Krzysztof Helt 已提交
1024
	if (err) {
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029 1030 1031 1032
		/* should never happen */
		DPRINTK("mode change aborted.  invalid var.\n");
		return -EINVAL;
	}

	bi = &cirrusfb_board_info[cinfo->btype];

	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
K
Krzysztof Helt 已提交
1033
	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
L
Linus Torvalds 已提交
1034 1035

	/* if debugging is enabled, all parameters get output before writing */
K
Krzysztof Helt 已提交
1036 1037
	DPRINTK("CRT0: %ld\n", regs.HorizTotal);
	vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
L
Linus Torvalds 已提交
1038

K
Krzysztof Helt 已提交
1039 1040
	DPRINTK("CRT1: %ld\n", regs.HorizDispEnd);
	vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
L
Linus Torvalds 已提交
1041

K
Krzysztof Helt 已提交
1042 1043
	DPRINTK("CRT2: %ld\n", regs.HorizBlankStart);
	vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
L
Linus Torvalds 已提交
1044

K
Krzysztof Helt 已提交
1045 1046 1047 1048
	/*  + 128: Compatible read */
	DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32);
	vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
		 128 + (regs.HorizBlankEnd % 32));
L
Linus Torvalds 已提交
1049

K
Krzysztof Helt 已提交
1050 1051
	DPRINTK("CRT4: %ld\n", regs.HorizSyncStart);
	vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
L
Linus Torvalds 已提交
1052 1053 1054 1055

	tmp = regs.HorizSyncEnd % 32;
	if (regs.HorizBlankEnd & 32)
		tmp += 128;
K
Krzysztof Helt 已提交
1056 1057
	DPRINTK("CRT5: %d\n", tmp);
	vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
L
Linus Torvalds 已提交
1058

K
Krzysztof Helt 已提交
1059 1060
	DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff);
	vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
L
Linus Torvalds 已提交
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076

	tmp = 16;		/* LineCompare bit #9 */
	if (regs.VertTotal & 256)
		tmp |= 1;
	if (regs.VertDispEnd & 256)
		tmp |= 2;
	if (regs.VertSyncStart & 256)
		tmp |= 4;
	if (regs.VertBlankStart & 256)
		tmp |= 8;
	if (regs.VertTotal & 512)
		tmp |= 32;
	if (regs.VertDispEnd & 512)
		tmp |= 64;
	if (regs.VertSyncStart & 512)
		tmp |= 128;
K
Krzysztof Helt 已提交
1077 1078
	DPRINTK("CRT7: %d\n", tmp);
	vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
L
Linus Torvalds 已提交
1079 1080 1081 1082 1083 1084

	tmp = 0x40;		/* LineCompare bit #8 */
	if (regs.VertBlankStart & 512)
		tmp |= 0x20;
	if (var->vmode & FB_VMODE_DOUBLE)
		tmp |= 0x80;
K
Krzysztof Helt 已提交
1085 1086
	DPRINTK("CRT9: %d\n", tmp);
	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
L
Linus Torvalds 已提交
1087

K
Krzysztof Helt 已提交
1088 1089
	DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff);
	vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff);
L
Linus Torvalds 已提交
1090

K
Krzysztof Helt 已提交
1091 1092
	DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32);
L
Linus Torvalds 已提交
1093

K
Krzysztof Helt 已提交
1094 1095
	DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff);
	vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff);
L
Linus Torvalds 已提交
1096

K
Krzysztof Helt 已提交
1097 1098
	DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff);
	vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff);
L
Linus Torvalds 已提交
1099

K
Krzysztof Helt 已提交
1100 1101
	DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
	vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff);
L
Linus Torvalds 已提交
1102

K
Krzysztof Helt 已提交
1103 1104
	DPRINTK("CRT18: 0xff\n");
	vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
L
Linus Torvalds 已提交
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117

	tmp = 0;
	if (var->vmode & FB_VMODE_INTERLACED)
		tmp |= 1;
	if (regs.HorizBlankEnd & 64)
		tmp |= 16;
	if (regs.HorizBlankEnd & 128)
		tmp |= 32;
	if (regs.VertBlankEnd & 256)
		tmp |= 64;
	if (regs.VertBlankEnd & 512)
		tmp |= 128;

K
Krzysztof Helt 已提交
1118 1119
	DPRINTK("CRT1a: %d\n", tmp);
	vga_wcrt(regbase, CL_CRT1A, tmp);
L
Linus Torvalds 已提交
1120 1121 1122 1123 1124 1125

	/* set VCLK0 */
	/* hardware RefClock: 14.31818 MHz */
	/* formula: VClk = (OSC * N) / (D * (1+P)) */
	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */

K
Krzysztof Helt 已提交
1126
	vga_wseq(regbase, CL_SEQRB, regs.nom);
L
Linus Torvalds 已提交
1127 1128 1129 1130
	tmp = regs.den << 1;
	if (regs.div != 0)
		tmp |= 1;

K
Krzysztof Helt 已提交
1131
	/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
L
Linus Torvalds 已提交
1132 1133 1134
	if ((cinfo->btype == BT_SD64) ||
	    (cinfo->btype == BT_ALPINE) ||
	    (cinfo->btype == BT_GD5480))
K
Krzysztof Helt 已提交
1135
		tmp |= 0x80;
L
Linus Torvalds 已提交
1136

K
Krzysztof Helt 已提交
1137 1138
	DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
	vga_wseq(regbase, CL_SEQR1B, tmp);
L
Linus Torvalds 已提交
1139 1140 1141

	if (regs.VertRes >= 1024)
		/* 1280x1024 */
K
Krzysztof Helt 已提交
1142
		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
L
Linus Torvalds 已提交
1143 1144 1145
	else
		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
		 * address wrap, no compat. */
K
Krzysztof Helt 已提交
1146
		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
L
Linus Torvalds 已提交
1147

K
Krzysztof Helt 已提交
1148 1149
/* HAEH?	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);
 * previously: 0x00  unlock VGA_CRTC_H_TOTAL..CRT7 */
L
Linus Torvalds 已提交
1150 1151 1152 1153

	/* don't know if it would hurt to also program this if no interlaced */
	/* mode is used, but I feel better this way.. :-) */
	if (var->vmode & FB_VMODE_INTERLACED)
K
Krzysztof Helt 已提交
1154
		vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
L
Linus Torvalds 已提交
1155
	else
K
Krzysztof Helt 已提交
1156
		vga_wcrt(regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */
L
Linus Torvalds 已提交
1157

K
Krzysztof Helt 已提交
1158
	vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0);
L
Linus Torvalds 已提交
1159 1160

	/* adjust horizontal/vertical sync type (low/high) */
K
Krzysztof Helt 已提交
1161 1162
	/* enable display memory & CRTC I/O address for color mode */
	tmp = 0x03;
L
Linus Torvalds 已提交
1163 1164 1165 1166
	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
		tmp |= 0x40;
	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
		tmp |= 0x80;
K
Krzysztof Helt 已提交
1167
	WGen(cinfo, VGA_MIS_W, tmp);
L
Linus Torvalds 已提交
1168

K
Krzysztof Helt 已提交
1169 1170 1171 1172 1173 1174
	/* Screen A Preset Row-Scan register */
	vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
	/* text cursor on and start line */
	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
	/* text cursor end line */
	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
L
Linus Torvalds 已提交
1175 1176 1177 1178 1179 1180 1181 1182 1183

	/******************************************************
	 *
	 * 1 bpp
	 *
	 */

	/* programming for different color depths */
	if (var->bits_per_pixel == 1) {
K
Krzysztof Helt 已提交
1184 1185
		DPRINTK("cirrusfb: preparing for 1 bit deep display\n");
		vga_wgfx(regbase, VGA_GFX_MODE, 0);	/* mode register */
L
Linus Torvalds 已提交
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195

		/* SR07 */
		switch (cinfo->btype) {
		case BT_SD64:
		case BT_PICCOLO:
		case BT_PICASSO:
		case BT_SPECTRUM:
		case BT_PICASSO4:
		case BT_ALPINE:
		case BT_GD5480:
K
Krzysztof Helt 已提交
1196 1197
			DPRINTK(" (for GD54xx)\n");
			vga_wseq(regbase, CL_SEQR7,
L
Linus Torvalds 已提交
1198 1199 1200 1201 1202
				  regs.multiplexing ?
					bi->sr07_1bpp_mux : bi->sr07_1bpp);
			break;

		case BT_LAGUNA:
K
Krzysztof Helt 已提交
1203 1204 1205
			DPRINTK(" (for GD546x)\n");
			vga_wseq(regbase, CL_SEQR7,
				vga_rseq(regbase, CL_SEQR7) & ~0x01);
L
Linus Torvalds 已提交
1206 1207 1208
			break;

		default:
K
Krzysztof Helt 已提交
1209
			printk(KERN_WARNING "cirrusfb: unknown Board\n");
L
Linus Torvalds 已提交
1210 1211 1212 1213 1214 1215
			break;
		}

		/* Extended Sequencer Mode */
		switch (cinfo->btype) {
		case BT_SD64:
K
Krzysztof Helt 已提交
1216 1217 1218 1219 1220 1221
			/* setting the SEQRF on SD64 is not necessary
			 * (only during init)
			 */
			DPRINTK("(for SD64)\n");
			/*  MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x1a);
L
Linus Torvalds 已提交
1222 1223 1224
			break;

		case BT_PICCOLO:
K
Krzysztof Helt 已提交
1225 1226 1227 1228 1229 1230
			DPRINTK("(for Piccolo)\n");
			/* ### ueberall 0x22? */
			/* ##vorher 1c MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
			/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
L
Linus Torvalds 已提交
1231 1232 1233
			break;

		case BT_PICASSO:
K
Krzysztof Helt 已提交
1234 1235 1236 1237 1238
			DPRINTK("(for Picasso)\n");
			/* ##vorher 22 MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
			/* ## vorher d0 avoid FIFO underruns..? */
			vga_wseq(regbase, CL_SEQRF, 0xd0);
L
Linus Torvalds 已提交
1239 1240 1241
			break;

		case BT_SPECTRUM:
K
Krzysztof Helt 已提交
1242 1243 1244 1245 1246 1247
			DPRINTK("(for Spectrum)\n");
			/* ### ueberall 0x22? */
			/* ##vorher 1c MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
			/* evtl d0? avoid FIFO underruns..? */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
L
Linus Torvalds 已提交
1248 1249 1250 1251 1252 1253
			break;

		case BT_PICASSO4:
		case BT_ALPINE:
		case BT_GD5480:
		case BT_LAGUNA:
K
Krzysztof Helt 已提交
1254
			DPRINTK(" (for GD54xx)\n");
L
Linus Torvalds 已提交
1255 1256 1257 1258
			/* do nothing */
			break;

		default:
K
Krzysztof Helt 已提交
1259
			printk(KERN_WARNING "cirrusfb: unknown Board\n");
L
Linus Torvalds 已提交
1260 1261 1262
			break;
		}

K
Krzysztof Helt 已提交
1263 1264
		/* pixel mask: pass-through for first plane */
		WGen(cinfo, VGA_PEL_MSK, 0x01);
L
Linus Torvalds 已提交
1265
		if (regs.multiplexing)
K
Krzysztof Helt 已提交
1266 1267
			/* hidden dac reg: 1280x1024 */
			WHDR(cinfo, 0x4a);
L
Linus Torvalds 已提交
1268
		else
K
Krzysztof Helt 已提交
1269 1270 1271 1272 1273 1274
			/* hidden dac: nothing */
			WHDR(cinfo, 0);
		/* memory mode: odd/even, ext. memory */
		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
		/* plane mask: only write to first plane */
		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
L
Linus Torvalds 已提交
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
		offset = var->xres_virtual / 16;
	}

	/******************************************************
	 *
	 * 8 bpp
	 *
	 */

	else if (var->bits_per_pixel == 8) {
K
Krzysztof Helt 已提交
1285
		DPRINTK("cirrusfb: preparing for 8 bit deep display\n");
L
Linus Torvalds 已提交
1286 1287 1288 1289 1290 1291 1292 1293
		switch (cinfo->btype) {
		case BT_SD64:
		case BT_PICCOLO:
		case BT_PICASSO:
		case BT_SPECTRUM:
		case BT_PICASSO4:
		case BT_ALPINE:
		case BT_GD5480:
K
Krzysztof Helt 已提交
1294 1295
			DPRINTK(" (for GD54xx)\n");
			vga_wseq(regbase, CL_SEQR7,
L
Linus Torvalds 已提交
1296 1297 1298 1299 1300
				  regs.multiplexing ?
					bi->sr07_8bpp_mux : bi->sr07_8bpp);
			break;

		case BT_LAGUNA:
K
Krzysztof Helt 已提交
1301 1302 1303
			DPRINTK(" (for GD546x)\n");
			vga_wseq(regbase, CL_SEQR7,
				vga_rseq(regbase, CL_SEQR7) | 0x01);
L
Linus Torvalds 已提交
1304 1305 1306
			break;

		default:
K
Krzysztof Helt 已提交
1307
			printk(KERN_WARNING "cirrusfb: unknown Board\n");
L
Linus Torvalds 已提交
1308 1309 1310 1311 1312
			break;
		}

		switch (cinfo->btype) {
		case BT_SD64:
K
Krzysztof Helt 已提交
1313 1314
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x1d);
L
Linus Torvalds 已提交
1315 1316 1317
			break;

		case BT_PICCOLO:
K
Krzysztof Helt 已提交
1318 1319 1320 1321
			/* ### vorher 1c MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
L
Linus Torvalds 已提交
1322 1323 1324
			break;

		case BT_PICASSO:
K
Krzysztof Helt 已提交
1325 1326 1327 1328
			/* ### vorher 1c MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
L
Linus Torvalds 已提交
1329 1330 1331
			break;

		case BT_SPECTRUM:
K
Krzysztof Helt 已提交
1332 1333 1334 1335
			/* ### vorher 1c MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
L
Linus Torvalds 已提交
1336 1337 1338 1339
			break;

		case BT_PICASSO4:
#ifdef CONFIG_ZORRO
K
Krzysztof Helt 已提交
1340 1341
			/* ### INCOMPLETE!! */
			vga_wseq(regbase, CL_SEQRF, 0xb8);
L
Linus Torvalds 已提交
1342
#endif
K
Krzysztof Helt 已提交
1343
/*	  		vga_wseq(regbase, CL_SEQR1F, 0x1c); */
L
Linus Torvalds 已提交
1344 1345 1346
			break;

		case BT_ALPINE:
K
Krzysztof Helt 已提交
1347 1348
			DPRINTK(" (for GD543x)\n");
			cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
L
Linus Torvalds 已提交
1349 1350 1351 1352 1353
			/* We already set SRF and SR1F */
			break;

		case BT_GD5480:
		case BT_LAGUNA:
K
Krzysztof Helt 已提交
1354
			DPRINTK(" (for GD54xx)\n");
L
Linus Torvalds 已提交
1355 1356 1357 1358
			/* do nothing */
			break;

		default:
K
Krzysztof Helt 已提交
1359
			printk(KERN_WARNING "cirrusfb: unknown Board\n");
L
Linus Torvalds 已提交
1360 1361 1362
			break;
		}

K
Krzysztof Helt 已提交
1363 1364 1365 1366
		/* mode register: 256 color mode */
		vga_wgfx(regbase, VGA_GFX_MODE, 64);
		/* pixel mask: pass-through all planes */
		WGen(cinfo, VGA_PEL_MSK, 0xff);
L
Linus Torvalds 已提交
1367
		if (regs.multiplexing)
K
Krzysztof Helt 已提交
1368 1369
			/* hidden dac reg: 1280x1024 */
			WHDR(cinfo, 0x4a);
L
Linus Torvalds 已提交
1370
		else
K
Krzysztof Helt 已提交
1371 1372 1373 1374 1375 1376
			/* hidden dac: nothing */
			WHDR(cinfo, 0);
		/* memory mode: chain4, ext. memory */
		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
		/* plane mask: enable writing to all 4 planes */
		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
L
Linus Torvalds 已提交
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
		offset = var->xres_virtual / 8;
	}

	/******************************************************
	 *
	 * 16 bpp
	 *
	 */

	else if (var->bits_per_pixel == 16) {
K
Krzysztof Helt 已提交
1387
		DPRINTK("cirrusfb: preparing for 16 bit deep display\n");
L
Linus Torvalds 已提交
1388 1389
		switch (cinfo->btype) {
		case BT_SD64:
K
Krzysztof Helt 已提交
1390 1391 1392 1393
			/* Extended Sequencer Mode: 256c col. mode */
			vga_wseq(regbase, CL_SEQR7, 0xf7);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x1e);
L
Linus Torvalds 已提交
1394 1395 1396
			break;

		case BT_PICCOLO:
K
Krzysztof Helt 已提交
1397 1398 1399 1400 1401
			vga_wseq(regbase, CL_SEQR7, 0x87);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
L
Linus Torvalds 已提交
1402 1403 1404
			break;

		case BT_PICASSO:
K
Krzysztof Helt 已提交
1405 1406 1407 1408 1409
			vga_wseq(regbase, CL_SEQR7, 0x27);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
L
Linus Torvalds 已提交
1410 1411 1412
			break;

		case BT_SPECTRUM:
K
Krzysztof Helt 已提交
1413 1414 1415 1416 1417
			vga_wseq(regbase, CL_SEQR7, 0x87);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
L
Linus Torvalds 已提交
1418 1419 1420
			break;

		case BT_PICASSO4:
K
Krzysztof Helt 已提交
1421 1422
			vga_wseq(regbase, CL_SEQR7, 0x27);
/*			vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
L
Linus Torvalds 已提交
1423 1424 1425
			break;

		case BT_ALPINE:
K
Krzysztof Helt 已提交
1426
			DPRINTK(" (for GD543x)\n");
L
Linus Torvalds 已提交
1427
			if (regs.HorizRes >= 1024)
K
Krzysztof Helt 已提交
1428
				vga_wseq(regbase, CL_SEQR7, 0xa7);
L
Linus Torvalds 已提交
1429
			else
K
Krzysztof Helt 已提交
1430 1431
				vga_wseq(regbase, CL_SEQR7, 0xa3);
			cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
L
Linus Torvalds 已提交
1432 1433 1434
			break;

		case BT_GD5480:
K
Krzysztof Helt 已提交
1435 1436
			DPRINTK(" (for GD5480)\n");
			vga_wseq(regbase, CL_SEQR7, 0x17);
L
Linus Torvalds 已提交
1437 1438 1439 1440
			/* We already set SRF and SR1F */
			break;

		case BT_LAGUNA:
K
Krzysztof Helt 已提交
1441 1442 1443
			DPRINTK(" (for GD546x)\n");
			vga_wseq(regbase, CL_SEQR7,
				vga_rseq(regbase, CL_SEQR7) & ~0x01);
L
Linus Torvalds 已提交
1444 1445 1446
			break;

		default:
K
Krzysztof Helt 已提交
1447
			printk(KERN_WARNING "CIRRUSFB: unknown Board\n");
L
Linus Torvalds 已提交
1448 1449 1450
			break;
		}

K
Krzysztof Helt 已提交
1451 1452 1453 1454
		/* mode register: 256 color mode */
		vga_wgfx(regbase, VGA_GFX_MODE, 64);
		/* pixel mask: pass-through all planes */
		WGen(cinfo, VGA_PEL_MSK, 0xff);
L
Linus Torvalds 已提交
1455
#ifdef CONFIG_PCI
K
Krzysztof Helt 已提交
1456
		WHDR(cinfo, 0xc0);	/* Copy Xbh */
L
Linus Torvalds 已提交
1457 1458
#elif defined(CONFIG_ZORRO)
		/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
K
Krzysztof Helt 已提交
1459
		WHDR(cinfo, 0xa0);	/* hidden dac reg: nothing special */
L
Linus Torvalds 已提交
1460
#endif
K
Krzysztof Helt 已提交
1461 1462 1463 1464
		/* memory mode: chain4, ext. memory */
		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
		/* plane mask: enable writing to all 4 planes */
		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
L
Linus Torvalds 已提交
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
		offset = var->xres_virtual / 4;
	}

	/******************************************************
	 *
	 * 32 bpp
	 *
	 */

	else if (var->bits_per_pixel == 32) {
K
Krzysztof Helt 已提交
1475
		DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n");
L
Linus Torvalds 已提交
1476 1477
		switch (cinfo->btype) {
		case BT_SD64:
K
Krzysztof Helt 已提交
1478 1479 1480 1481
			/* Extended Sequencer Mode: 256c col. mode */
			vga_wseq(regbase, CL_SEQR7, 0xf9);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x1e);
L
Linus Torvalds 已提交
1482 1483 1484
			break;

		case BT_PICCOLO:
K
Krzysztof Helt 已提交
1485 1486 1487 1488 1489
			vga_wseq(regbase, CL_SEQR7, 0x85);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
L
Linus Torvalds 已提交
1490 1491 1492
			break;

		case BT_PICASSO:
K
Krzysztof Helt 已提交
1493 1494 1495 1496 1497
			vga_wseq(regbase, CL_SEQR7, 0x25);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
L
Linus Torvalds 已提交
1498 1499 1500
			break;

		case BT_SPECTRUM:
K
Krzysztof Helt 已提交
1501 1502 1503 1504 1505
			vga_wseq(regbase, CL_SEQR7, 0x85);
			/* Fast Page-Mode writes */
			vga_wseq(regbase, CL_SEQRF, 0xb0);
			/* MCLK select */
			vga_wseq(regbase, CL_SEQR1F, 0x22);
L
Linus Torvalds 已提交
1506 1507 1508
			break;

		case BT_PICASSO4:
K
Krzysztof Helt 已提交
1509 1510
			vga_wseq(regbase, CL_SEQR7, 0x25);
/*			vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
L
Linus Torvalds 已提交
1511 1512 1513
			break;

		case BT_ALPINE:
K
Krzysztof Helt 已提交
1514 1515 1516
			DPRINTK(" (for GD543x)\n");
			vga_wseq(regbase, CL_SEQR7, 0xa9);
			cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
L
Linus Torvalds 已提交
1517 1518 1519
			break;

		case BT_GD5480:
K
Krzysztof Helt 已提交
1520 1521
			DPRINTK(" (for GD5480)\n");
			vga_wseq(regbase, CL_SEQR7, 0x19);
L
Linus Torvalds 已提交
1522 1523 1524 1525
			/* We already set SRF and SR1F */
			break;

		case BT_LAGUNA:
K
Krzysztof Helt 已提交
1526 1527 1528
			DPRINTK(" (for GD546x)\n");
			vga_wseq(regbase, CL_SEQR7,
				vga_rseq(regbase, CL_SEQR7) & ~0x01);
L
Linus Torvalds 已提交
1529 1530 1531
			break;

		default:
K
Krzysztof Helt 已提交
1532
			printk(KERN_WARNING "cirrusfb: unknown Board\n");
L
Linus Torvalds 已提交
1533 1534 1535
			break;
		}

K
Krzysztof Helt 已提交
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
		/* mode register: 256 color mode */
		vga_wgfx(regbase, VGA_GFX_MODE, 64);
		/* pixel mask: pass-through all planes */
		WGen(cinfo, VGA_PEL_MSK, 0xff);
		/* hidden dac reg: 8-8-8 mode (24 or 32) */
		WHDR(cinfo, 0xc5);
		/* memory mode: chain4, ext. memory */
		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
		/* plane mask: enable writing to all 4 planes */
		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
L
Linus Torvalds 已提交
1546 1547 1548 1549 1550 1551 1552 1553 1554
		offset = var->xres_virtual / 4;
	}

	/******************************************************
	 *
	 * unknown/unsupported bpp
	 *
	 */

K
Krzysztof Helt 已提交
1555 1556 1557
	else
		printk(KERN_ERR "cirrusfb: What's this?? "
			" requested color depth == %d.\n",
L
Linus Torvalds 已提交
1558 1559
			var->bits_per_pixel);

K
Krzysztof Helt 已提交
1560
	vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff);
L
Linus Torvalds 已提交
1561 1562 1563 1564
	tmp = 0x22;
	if (offset & 0x100)
		tmp |= 0x10;	/* offset overflow bit */

K
Krzysztof Helt 已提交
1565 1566
	/* screen start addr #16-18, fastpagemode cycles */
	vga_wcrt(regbase, CL_CRT1B, tmp);
L
Linus Torvalds 已提交
1567 1568 1569 1570 1571

	if (cinfo->btype == BT_SD64 ||
	    cinfo->btype == BT_PICASSO4 ||
	    cinfo->btype == BT_ALPINE ||
	    cinfo->btype == BT_GD5480)
K
Krzysztof Helt 已提交
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591
		/* screen start address bit 19 */
		vga_wcrt(regbase, CL_CRT1D, 0x00);

	/* text cursor location high */
	vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0);
	/* text cursor location low */
	vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0);
	/* underline row scanline = at very bottom */
	vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);

	/* controller mode */
	vga_wattr(regbase, VGA_ATC_MODE, 1);
	/* overscan (border) color */
	vga_wattr(regbase, VGA_ATC_OVERSCAN, 0);
	/* color plane enable */
	vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15);
	/* pixel panning */
	vga_wattr(regbase, CL_AR33, 0);
	/* color select */
	vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0);
L
Linus Torvalds 已提交
1592 1593 1594

	/* [ EGS: SetOffset(); ] */
	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
K
Krzysztof Helt 已提交
1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
	AttrOn(cinfo);

	/* set/reset register */
	vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0);
	/* set/reset enable */
	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0);
	/* color compare */
	vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0);
	/* data rotate */
	vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0);
	/* read map select */
	vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0);
	/* miscellaneous register */
	vga_wgfx(regbase, VGA_GFX_MISC, 1);
	/* color don't care */
	vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15);
	/* bit mask */
	vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255);

	/* graphics cursor attributes: nothing special */
	vga_wseq(regbase, CL_SEQR12, 0x0);
L
Linus Torvalds 已提交
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625

	/* finally, turn on everything - turn off "FullBandwidth" bit */
	/* also, set "DotClock%2" bit where requested */
	tmp = 0x01;

/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
    if (var->vmode & FB_VMODE_CLOCK_HALVE)
	tmp |= 0x08;
*/

K
Krzysztof Helt 已提交
1626 1627
	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
	DPRINTK("CL_SEQR1: %d\n", tmp);
L
Linus Torvalds 已提交
1628 1629 1630 1631 1632 1633 1634

	cinfo->currentmode = regs;
	info->fix.type = regs.type;
	info->fix.visual = regs.visual;
	info->fix.line_length = regs.line_length;

	/* pan to requested offset */
K
Krzysztof Helt 已提交
1635
	cirrusfb_pan_display(var, info);
L
Linus Torvalds 已提交
1636 1637

#ifdef CIRRUSFB_DEBUG
K
Krzysztof Helt 已提交
1638
	cirrusfb_dump();
L
Linus Torvalds 已提交
1639 1640
#endif

K
Krzysztof Helt 已提交
1641
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
1642 1643 1644 1645 1646
	return 0;
}

/* for some reason incomprehensible to me, cirrusfb requires that you write
 * the registers twice for the settings to take..grr. -dte */
K
Krzysztof Helt 已提交
1647
static int cirrusfb_set_par(struct fb_info *info)
L
Linus Torvalds 已提交
1648
{
K
Krzysztof Helt 已提交
1649 1650
	cirrusfb_set_par_foo(info);
	return cirrusfb_set_par_foo(info);
L
Linus Torvalds 已提交
1651 1652
}

K
Krzysztof Helt 已提交
1653 1654 1655
static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
			      unsigned blue, unsigned transp,
			      struct fb_info *info)
L
Linus Torvalds 已提交
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
{
	struct cirrusfb_info *cinfo = info->par;

	if (regno > 255)
		return -EINVAL;

	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
		u32 v;
		red >>= (16 - info->var.red.length);
		green >>= (16 - info->var.green.length);
		blue >>= (16 - info->var.blue.length);

K
Krzysztof Helt 已提交
1668
		if (regno >= 16)
L
Linus Torvalds 已提交
1669 1670 1671 1672 1673 1674
			return 1;
		v = (red << info->var.red.offset) |
		    (green << info->var.green.offset) |
		    (blue << info->var.blue.offset);

		switch (info->var.bits_per_pixel) {
K
Krzysztof Helt 已提交
1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
		case 8:
			cinfo->pseudo_palette[regno] = v;
			break;
		case 16:
			cinfo->pseudo_palette[regno] = v;
			break;
		case 24:
		case 32:
			cinfo->pseudo_palette[regno] = v;
			break;
L
Linus Torvalds 已提交
1685 1686 1687 1688 1689 1690 1691 1692
		}
		return 0;
	}

	cinfo->palette[regno].red = red;
	cinfo->palette[regno].green = green;
	cinfo->palette[regno].blue = blue;

K
Krzysztof Helt 已提交
1693 1694
	if (info->var.bits_per_pixel == 8)
		WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
L
Linus Torvalds 已提交
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704

	return 0;

}

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

	performs display panning - provided hardware permits this
**************************************************************************/
K
Krzysztof Helt 已提交
1705 1706
static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
				struct fb_info *info)
L
Linus Torvalds 已提交
1707 1708 1709 1710 1711 1712 1713
{
	int xoffset = 0;
	int yoffset = 0;
	unsigned long base;
	unsigned char tmp = 0, tmp2 = 0, xpix;
	struct cirrusfb_info *cinfo = info->par;

K
Krzysztof Helt 已提交
1714 1715
	DPRINTK("ENTER\n");
	DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
L
Linus Torvalds 已提交
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737

	/* no range checks for xoffset and yoffset,   */
	/* as fb_pan_display has already done this */
	if (var->vmode & FB_VMODE_YWRAP)
		return -EINVAL;

	info->var.xoffset = var->xoffset;
	info->var.yoffset = var->yoffset;

	xoffset = var->xoffset * info->var.bits_per_pixel / 8;
	yoffset = var->yoffset;

	base = yoffset * cinfo->currentmode.line_length + xoffset;

	if (info->var.bits_per_pixel == 1) {
		/* base is already correct */
		xpix = (unsigned char) (var->xoffset % 8);
	} else {
		base /= 4;
		xpix = (unsigned char) ((xoffset % 4) * 2);
	}

K
Krzysztof Helt 已提交
1738
	cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
L
Linus Torvalds 已提交
1739 1740

	/* lower 8 + 8 bits of screen start address */
K
Krzysztof Helt 已提交
1741 1742 1743 1744
	vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO,
		 (unsigned char) (base & 0xff));
	vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI,
		 (unsigned char) (base >> 8));
L
Linus Torvalds 已提交
1745 1746 1747 1748 1749 1750 1751 1752 1753

	/* construct bits 16, 17 and 18 of screen start address */
	if (base & 0x10000)
		tmp |= 0x01;
	if (base & 0x20000)
		tmp |= 0x04;
	if (base & 0x40000)
		tmp |= 0x08;

K
Krzysztof Helt 已提交
1754 1755 1756
	/* 0xf2 is %11110010, exclude tmp bits */
	tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp;
	vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2);
L
Linus Torvalds 已提交
1757 1758 1759 1760 1761 1762

	/* construct bit 19 of screen start address */
	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
		tmp2 = 0;
		if (base & 0x80000)
			tmp2 = 0x80;
K
Krzysztof Helt 已提交
1763
		vga_wcrt(cinfo->regbase, CL_CRT1D, tmp2);
L
Linus Torvalds 已提交
1764 1765
	}

K
Krzysztof Helt 已提交
1766 1767 1768 1769
	/* write pixel panning value to AR33; this does not quite work in 8bpp
	 *
	 * ### Piccolo..? Will this work?
	 */
L
Linus Torvalds 已提交
1770
	if (info->var.bits_per_pixel == 1)
K
Krzysztof Helt 已提交
1771
		vga_wattr(cinfo->regbase, CL_AR33, xpix);
L
Linus Torvalds 已提交
1772

K
Krzysztof Helt 已提交
1773
	cirrusfb_WaitBLT(cinfo->regbase);
L
Linus Torvalds 已提交
1774

K
Krzysztof Helt 已提交
1775 1776
	DPRINTK("EXIT\n");
	return 0;
L
Linus Torvalds 已提交
1777 1778
}

K
Krzysztof Helt 已提交
1779
static int cirrusfb_blank(int blank_mode, struct fb_info *info)
L
Linus Torvalds 已提交
1780 1781
{
	/*
K
Krzysztof Helt 已提交
1782 1783 1784 1785 1786 1787 1788 1789 1790
	 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
	 * then the caller blanks by setting the CLUT (Color Look Up Table)
	 * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
	 * failed due to e.g. a video mode which doesn't support it.
	 * Implements VESA suspend and powerdown modes on hardware that
	 * supports disabling hsync/vsync:
	 *   blank_mode == 2: suspend vsync
	 *   blank_mode == 3: suspend hsync
	 *   blank_mode == 4: powerdown
L
Linus Torvalds 已提交
1791 1792 1793 1794 1795
	 */
	unsigned char val;
	struct cirrusfb_info *cinfo = info->par;
	int current_mode = cinfo->blank_mode;

K
Krzysztof Helt 已提交
1796
	DPRINTK("ENTER, blank mode = %d\n", blank_mode);
L
Linus Torvalds 已提交
1797 1798 1799

	if (info->state != FBINFO_STATE_RUNNING ||
	    current_mode == blank_mode) {
K
Krzysztof Helt 已提交
1800
		DPRINTK("EXIT, returning 0\n");
L
Linus Torvalds 已提交
1801 1802 1803 1804 1805 1806 1807
		return 0;
	}

	/* Undo current */
	if (current_mode == FB_BLANK_NORMAL ||
	    current_mode == FB_BLANK_UNBLANK) {
		/* unblank the screen */
K
Krzysztof Helt 已提交
1808 1809 1810
		val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
		/* clear "FullBandwidth" bit */
		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf);
L
Linus Torvalds 已提交
1811
		/* and undo VESA suspend trickery */
K
Krzysztof Helt 已提交
1812
		vga_wgfx(cinfo->regbase, CL_GRE, 0x00);
L
Linus Torvalds 已提交
1813 1814 1815
	}

	/* set new */
K
Krzysztof Helt 已提交
1816
	if (blank_mode > FB_BLANK_NORMAL) {
L
Linus Torvalds 已提交
1817
		/* blank the screen */
K
Krzysztof Helt 已提交
1818 1819 1820
		val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
		/* set "FullBandwidth" bit */
		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20);
L
Linus Torvalds 已提交
1821 1822 1823 1824 1825 1826 1827
	}

	switch (blank_mode) {
	case FB_BLANK_UNBLANK:
	case FB_BLANK_NORMAL:
		break;
	case FB_BLANK_VSYNC_SUSPEND:
K
Krzysztof Helt 已提交
1828
		vga_wgfx(cinfo->regbase, CL_GRE, 0x04);
L
Linus Torvalds 已提交
1829 1830
		break;
	case FB_BLANK_HSYNC_SUSPEND:
K
Krzysztof Helt 已提交
1831
		vga_wgfx(cinfo->regbase, CL_GRE, 0x02);
L
Linus Torvalds 已提交
1832 1833
		break;
	case FB_BLANK_POWERDOWN:
K
Krzysztof Helt 已提交
1834
		vga_wgfx(cinfo->regbase, CL_GRE, 0x06);
L
Linus Torvalds 已提交
1835 1836
		break;
	default:
K
Krzysztof Helt 已提交
1837
		DPRINTK("EXIT, returning 1\n");
L
Linus Torvalds 已提交
1838 1839 1840 1841
		return 1;
	}

	cinfo->blank_mode = blank_mode;
K
Krzysztof Helt 已提交
1842
	DPRINTK("EXIT, returning 0\n");
L
Linus Torvalds 已提交
1843 1844 1845 1846 1847 1848 1849 1850

	/* Let fbcon do a soft blank for us */
	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
}
/**** END   Hardware specific Routines **************************************/
/****************************************************************************/
/**** BEGIN Internal Routines ***********************************************/

K
Krzysztof Helt 已提交
1851
static void init_vgachip(struct cirrusfb_info *cinfo)
L
Linus Torvalds 已提交
1852 1853 1854
{
	const struct cirrusfb_board_info_rec *bi;

K
Krzysztof Helt 已提交
1855
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
1856

K
Krzysztof Helt 已提交
1857
	assert(cinfo != NULL);
L
Linus Torvalds 已提交
1858 1859 1860 1861 1862 1863

	bi = &cirrusfb_board_info[cinfo->btype];

	/* reset board globally */
	switch (cinfo->btype) {
	case BT_PICCOLO:
K
Krzysztof Helt 已提交
1864 1865 1866 1867
		WSFR(cinfo, 0x01);
		udelay(500);
		WSFR(cinfo, 0x51);
		udelay(500);
L
Linus Torvalds 已提交
1868 1869
		break;
	case BT_PICASSO:
K
Krzysztof Helt 已提交
1870 1871
		WSFR2(cinfo, 0xff);
		udelay(500);
L
Linus Torvalds 已提交
1872 1873 1874
		break;
	case BT_SD64:
	case BT_SPECTRUM:
K
Krzysztof Helt 已提交
1875 1876 1877 1878
		WSFR(cinfo, 0x1f);
		udelay(500);
		WSFR(cinfo, 0x4f);
		udelay(500);
L
Linus Torvalds 已提交
1879 1880
		break;
	case BT_PICASSO4:
K
Krzysztof Helt 已提交
1881 1882 1883 1884 1885 1886 1887 1888 1889
		/* disable flickerfixer */
		vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
		mdelay(100);
		/* from Klaus' NetBSD driver: */
		vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
		/* put blitter into 542x compat */
		vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
		/* mode */
		vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
L
Linus Torvalds 已提交
1890 1891 1892
		break;

	case BT_GD5480:
K
Krzysztof Helt 已提交
1893 1894
		/* from Klaus' NetBSD driver: */
		vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
L
Linus Torvalds 已提交
1895 1896 1897 1898 1899 1900 1901
		break;

	case BT_ALPINE:
		/* Nothing to do to reset the board. */
		break;

	default:
K
Krzysztof Helt 已提交
1902
		printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n");
L
Linus Torvalds 已提交
1903 1904 1905
		break;
	}

K
Krzysztof Helt 已提交
1906
	assert(cinfo->size > 0); /* make sure RAM size set by this point */
L
Linus Torvalds 已提交
1907 1908 1909

	/* the P4 is not fully initialized here; I rely on it having been */
	/* inited under AmigaOS already, which seems to work just fine    */
K
Krzysztof Helt 已提交
1910
	/* (Klaus advised to do it this way)			      */
L
Linus Torvalds 已提交
1911 1912

	if (cinfo->btype != BT_PICASSO4) {
K
Krzysztof Helt 已提交
1913 1914 1915
		WGen(cinfo, CL_VSSM, 0x10);	/* EGS: 0x16 */
		WGen(cinfo, CL_POS102, 0x01);
		WGen(cinfo, CL_VSSM, 0x08);	/* EGS: 0x0e */
L
Linus Torvalds 已提交
1916 1917

		if (cinfo->btype != BT_SD64)
K
Krzysztof Helt 已提交
1918
			WGen(cinfo, CL_VSSM2, 0x01);
L
Linus Torvalds 已提交
1919

K
Krzysztof Helt 已提交
1920 1921
		/* reset sequencer logic */
		vga_wseq(cinfo->regbase, CL_SEQR0, 0x03);
L
Linus Torvalds 已提交
1922

K
Krzysztof Helt 已提交
1923 1924 1925 1926 1927 1928
		/* FullBandwidth (video off) and 8/9 dot clock */
		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
		/* polarity (-/-), disable access to display memory,
		 * VGA_CRTC_START_HI base address: color
		 */
		WGen(cinfo, VGA_MIS_W, 0xc1);
L
Linus Torvalds 已提交
1929

K
Krzysztof Helt 已提交
1930 1931 1932 1933
		/* "magic cookie" - doesn't make any sense to me.. */
/*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
		/* unlock all extension registers */
		vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
L
Linus Torvalds 已提交
1934

K
Krzysztof Helt 已提交
1935 1936
		/* reset blitter */
		vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
L
Linus Torvalds 已提交
1937 1938 1939

		switch (cinfo->btype) {
		case BT_GD5480:
K
Krzysztof Helt 已提交
1940
			vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
L
Linus Torvalds 已提交
1941 1942 1943 1944
			break;
		case BT_ALPINE:
			break;
		case BT_SD64:
K
Krzysztof Helt 已提交
1945
			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
L
Linus Torvalds 已提交
1946 1947
			break;
		default:
K
Krzysztof Helt 已提交
1948 1949
			vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
L
Linus Torvalds 已提交
1950 1951 1952
			break;
		}
	}
K
Krzysztof Helt 已提交
1953 1954 1955 1956 1957 1958
	/* plane mask: nothing */
	vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
	/* character map select: doesn't even matter in gx mode */
	vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
	/* memory mode: chain-4, no odd/even, ext. memory */
	vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e);
L
Linus Torvalds 已提交
1959 1960 1961

	/* controller-internal base address of video memory */
	if (bi->init_sr07)
K
Krzysztof Helt 已提交
1962
		vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
L
Linus Torvalds 已提交
1963

K
Krzysztof Helt 已提交
1964 1965
	/*  vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
	/* EEPROM control: shouldn't be necessary to write to this at all.. */
L
Linus Torvalds 已提交
1966

K
Krzysztof Helt 已提交
1967 1968 1969 1970 1971 1972 1973 1974
	/* graphics cursor X position (incomplete; position gives rem. 3 bits */
	vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
	/* graphics cursor Y position (..."... ) */
	vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
	/* graphics cursor attributes */
	vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
	/* graphics cursor pattern address */
	vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
L
Linus Torvalds 已提交
1975 1976 1977

	/* writing these on a P4 might give problems..  */
	if (cinfo->btype != BT_PICASSO4) {
K
Krzysztof Helt 已提交
1978 1979 1980 1981
		/* configuration readback and ext. color */
		vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
		/* signature generator */
		vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
L
Linus Torvalds 已提交
1982 1983 1984 1985
	}

	/* MCLK select etc. */
	if (bi->init_sr1f)
K
Krzysztof Helt 已提交
1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
		vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f);

	/* Screen A preset row scan: none */
	vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
	/* Text cursor start: disable text cursor */
	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
	/* Text cursor end: - */
	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
	/* Screen start address high: 0 */
	vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00);
	/* Screen start address low: 0 */
	vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00);
	/* text cursor location high: 0 */
	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
	/* text cursor location low: 0 */
	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);

	/* Underline Row scanline: - */
	vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
	/* mode control: timing enable, byte mode, no compat modes */
	vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3);
	/* Line Compare: not needed */
	vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00);
L
Linus Torvalds 已提交
2009
	/* ### add 0x40 for text modes with > 30 MHz pixclock */
K
Krzysztof Helt 已提交
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
	/* ext. display controls: ext.adr. wrap */
	vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);

	/* Set/Reset registes: - */
	vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
	/* Set/Reset enable: - */
	vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
	/* Color Compare: - */
	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
	/* Data Rotate: - */
	vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
	/* Read Map Select: - */
	vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
	vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
	/* Miscellaneous: memory map base address, graphics mode */
	vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
	/* Color Don't care: involve all planes */
	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
	/* Bit Mask: no mask at all */
	vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
L
Linus Torvalds 已提交
2031
	if (cinfo->btype == BT_ALPINE)
K
Krzysztof Helt 已提交
2032 2033
		/* (5434 can't have bit 3 set for bitblt) */
		vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
L
Linus Torvalds 已提交
2034
	else
K
Krzysztof Helt 已提交
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075
	/* Graphics controller mode extensions: finer granularity,
	 * 8byte data latches
	 */
		vga_wgfx(cinfo->regbase, CL_GRB, 0x28);

	vga_wgfx(cinfo->regbase, CL_GRC, 0xff);	/* Color Key compare: - */
	vga_wgfx(cinfo->regbase, CL_GRD, 0x00);	/* Color Key compare mask: - */
	vga_wgfx(cinfo->regbase, CL_GRE, 0x00);	/* Miscellaneous control: - */
	/* Background color byte 1: - */
	/*  vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
	/*  vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */

	/* Attribute Controller palette registers: "identity mapping" */
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);

	/* Attribute Controller mode: graphics mode */
	vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
	/* Overscan color reg.: reg. 0 */
	vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
	/* Color Plane enable: Enable all 4 planes */
	vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
/* ###  vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
	/* Color Select: - */
	vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);

	WGen(cinfo, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
L
Linus Torvalds 已提交
2076 2077

	if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
K
Krzysztof Helt 已提交
2078 2079 2080 2081
	/* polarity (-/-), enable display mem,
	 * VGA_CRTC_START_HI i/o base = color
	 */
		WGen(cinfo, VGA_MIS_W, 0xc3);
L
Linus Torvalds 已提交
2082

K
Krzysztof Helt 已提交
2083 2084 2085 2086
	/* BLT Start/status: Blitter reset */
	vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
	/* - " -	   : "end-of-reset" */
	vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
L
Linus Torvalds 已提交
2087 2088

	/* misc... */
K
Krzysztof Helt 已提交
2089
	WHDR(cinfo, 0);	/* Hidden DAC register: - */
L
Linus Torvalds 已提交
2090

K
Krzysztof Helt 已提交
2091 2092 2093
	printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n",
		cinfo->size);
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2094 2095 2096
	return;
}

K
Krzysztof Helt 已提交
2097
static void switch_monitor(struct cirrusfb_info *cinfo, int on)
L
Linus Torvalds 已提交
2098 2099 2100 2101
{
#ifdef CONFIG_ZORRO /* only works on Zorro boards */
	static int IsOn = 0;	/* XXX not ok for multiple boards */

K
Krzysztof Helt 已提交
2102
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2103 2104 2105 2106 2107 2108 2109 2110 2111

	if (cinfo->btype == BT_PICASSO4)
		return;		/* nothing to switch */
	if (cinfo->btype == BT_ALPINE)
		return;		/* nothing to switch */
	if (cinfo->btype == BT_GD5480)
		return;		/* nothing to switch */
	if (cinfo->btype == BT_PICASSO) {
		if ((on && !IsOn) || (!on && IsOn))
K
Krzysztof Helt 已提交
2112
			WSFR(cinfo, 0xff);
L
Linus Torvalds 已提交
2113

K
Krzysztof Helt 已提交
2114
		DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2115 2116 2117 2118 2119
		return;
	}
	if (on) {
		switch (cinfo->btype) {
		case BT_SD64:
K
Krzysztof Helt 已提交
2120
			WSFR(cinfo, cinfo->SFR | 0x21);
L
Linus Torvalds 已提交
2121 2122
			break;
		case BT_PICCOLO:
K
Krzysztof Helt 已提交
2123
			WSFR(cinfo, cinfo->SFR | 0x28);
L
Linus Torvalds 已提交
2124 2125
			break;
		case BT_SPECTRUM:
K
Krzysztof Helt 已提交
2126
			WSFR(cinfo, 0x6f);
L
Linus Torvalds 已提交
2127 2128 2129 2130 2131 2132
			break;
		default: /* do nothing */ break;
		}
	} else {
		switch (cinfo->btype) {
		case BT_SD64:
K
Krzysztof Helt 已提交
2133
			WSFR(cinfo, cinfo->SFR & 0xde);
L
Linus Torvalds 已提交
2134 2135
			break;
		case BT_PICCOLO:
K
Krzysztof Helt 已提交
2136
			WSFR(cinfo, cinfo->SFR & 0xd7);
L
Linus Torvalds 已提交
2137 2138
			break;
		case BT_SPECTRUM:
K
Krzysztof Helt 已提交
2139
			WSFR(cinfo, 0x4f);
L
Linus Torvalds 已提交
2140 2141 2142 2143 2144
			break;
		default: /* do nothing */ break;
		}
	}

K
Krzysztof Helt 已提交
2145
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156
#endif /* CONFIG_ZORRO */
}

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

static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo,
				   const struct fb_fillrect *region)
{
	int m; /* bytes per pixel */
2157 2158 2159
	u32 color = (cinfo->info->fix.visual == FB_VISUAL_TRUECOLOR) ?
		cinfo->pseudo_palette[region->color] : region->color;

K
Krzysztof Helt 已提交
2160 2161 2162
	if (cinfo->info->var.bits_per_pixel == 1) {
		cirrusfb_RectFill(cinfo->regbase,
				  cinfo->info->var.bits_per_pixel,
L
Linus Torvalds 已提交
2163 2164
				  region->dx / 8, region->dy,
				  region->width / 8, region->height,
2165
				  color,
L
Linus Torvalds 已提交
2166 2167
				  cinfo->currentmode.line_length);
	} else {
K
Krzysztof Helt 已提交
2168 2169 2170
		m = (cinfo->info->var.bits_per_pixel + 7) / 8;
		cirrusfb_RectFill(cinfo->regbase,
				  cinfo->info->var.bits_per_pixel,
L
Linus Torvalds 已提交
2171 2172
				  region->dx * m, region->dy,
				  region->width * m, region->height,
2173
				  color,
L
Linus Torvalds 已提交
2174 2175 2176 2177 2178
				  cinfo->currentmode.line_length);
	}
	return;
}

K
Krzysztof Helt 已提交
2179 2180
static void cirrusfb_fillrect(struct fb_info *info,
			      const struct fb_fillrect *region)
L
Linus Torvalds 已提交
2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
{
	struct cirrusfb_info *cinfo = info->par;
	struct fb_fillrect modded;
	int vxres, vyres;

	if (info->state != FBINFO_STATE_RUNNING)
		return;
	if (info->flags & FBINFO_HWACCEL_DISABLED) {
		cfb_fillrect(info, region);
		return;
	}

	vxres = info->var.xres_virtual;
	vyres = info->var.yres_virtual;

	memcpy(&modded, region, sizeof(struct fb_fillrect));

K
Krzysztof Helt 已提交
2198
	if (!modded.width || !modded.height ||
L
Linus Torvalds 已提交
2199 2200 2201
	   modded.dx >= vxres || modded.dy >= vyres)
		return;

K
Krzysztof Helt 已提交
2202 2203 2204 2205
	if (modded.dx + modded.width  > vxres)
		modded.width  = vxres - modded.dx;
	if (modded.dy + modded.height > vyres)
		modded.height = vyres - modded.dy;
L
Linus Torvalds 已提交
2206 2207 2208 2209 2210 2211 2212 2213

	cirrusfb_prim_fillrect(cinfo, &modded);
}

static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo,
				   const struct fb_copyarea *area)
{
	int m; /* bytes per pixel */
K
Krzysztof Helt 已提交
2214
	if (cinfo->info->var.bits_per_pixel == 1) {
L
Linus Torvalds 已提交
2215 2216 2217 2218 2219 2220
		cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
				area->sx / 8, area->sy,
				area->dx / 8, area->dy,
				area->width / 8, area->height,
				cinfo->currentmode.line_length);
	} else {
K
Krzysztof Helt 已提交
2221
		m = (cinfo->info->var.bits_per_pixel + 7) / 8;
L
Linus Torvalds 已提交
2222 2223 2224 2225 2226 2227 2228 2229 2230
		cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
				area->sx * m, area->sy,
				area->dx * m, area->dy,
				area->width * m, area->height,
				cinfo->currentmode.line_length);
	}
	return;
}

K
Krzysztof Helt 已提交
2231 2232
static void cirrusfb_copyarea(struct fb_info *info,
			      const struct fb_copyarea *area)
L
Linus Torvalds 已提交
2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253
{
	struct cirrusfb_info *cinfo = info->par;
	struct fb_copyarea modded;
	u32 vxres, vyres;
	modded.sx = area->sx;
	modded.sy = area->sy;
	modded.dx = area->dx;
	modded.dy = area->dy;
	modded.width  = area->width;
	modded.height = area->height;

	if (info->state != FBINFO_STATE_RUNNING)
		return;
	if (info->flags & FBINFO_HWACCEL_DISABLED) {
		cfb_copyarea(info, area);
		return;
	}

	vxres = info->var.xres_virtual;
	vyres = info->var.yres_virtual;

K
Krzysztof Helt 已提交
2254
	if (!modded.width || !modded.height ||
L
Linus Torvalds 已提交
2255 2256 2257 2258
	   modded.sx >= vxres || modded.sy >= vyres ||
	   modded.dx >= vxres || modded.dy >= vyres)
		return;

K
Krzysztof Helt 已提交
2259 2260 2261 2262 2263 2264 2265 2266
	if (modded.sx + modded.width > vxres)
		modded.width = vxres - modded.sx;
	if (modded.dx + modded.width > vxres)
		modded.width = vxres - modded.dx;
	if (modded.sy + modded.height > vyres)
		modded.height = vyres - modded.sy;
	if (modded.dy + modded.height > vyres)
		modded.height = vyres - modded.dy;
L
Linus Torvalds 已提交
2267 2268 2269 2270

	cirrusfb_prim_copyarea(cinfo, &modded);
}

K
Krzysztof Helt 已提交
2271 2272
static void cirrusfb_imageblit(struct fb_info *info,
			       const struct fb_image *image)
L
Linus Torvalds 已提交
2273 2274 2275
{
	struct cirrusfb_info *cinfo = info->par;

K
Krzysztof Helt 已提交
2276
	cirrusfb_WaitBLT(cinfo->regbase);
L
Linus Torvalds 已提交
2277 2278 2279 2280 2281 2282
	cfb_imageblit(info, image);
}

#ifdef CONFIG_PPC_PREP
#define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
#define PREP_IO_BASE    ((volatile unsigned char *) 0x80000000)
K
Krzysztof Helt 已提交
2283
static void get_prep_addrs(unsigned long *display, unsigned long *registers)
L
Linus Torvalds 已提交
2284
{
K
Krzysztof Helt 已提交
2285
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2286 2287 2288 2289

	*display = PREP_VIDEO_BASE;
	*registers = (unsigned long) PREP_IO_BASE;

K
Krzysztof Helt 已提交
2290
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2291 2292 2293 2294 2295
}

#endif				/* CONFIG_PPC_PREP */

#ifdef CONFIG_PCI
K
Krzysztof Helt 已提交
2296
static int release_io_ports;
L
Linus Torvalds 已提交
2297 2298 2299 2300 2301

/* 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. */
K
Krzysztof Helt 已提交
2302
static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase)
L
Linus Torvalds 已提交
2303 2304 2305 2306
{
	unsigned long mem;
	unsigned char SRF;

K
Krzysztof Helt 已提交
2307
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2308

K
Krzysztof Helt 已提交
2309
	SRF = vga_rseq(regbase, CL_SEQRF);
L
Linus Torvalds 已提交
2310
	switch ((SRF & 0x18)) {
K
Krzysztof Helt 已提交
2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324
	case 0x08:
		mem = 512 * 1024;
		break;
	case 0x10:
		mem = 1024 * 1024;
		break;
	/* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
	 * on the 5430.
	 */
	case 0x18:
		mem = 2048 * 1024;
		break;
	default:
		printk(KERN_WARNING "CLgenfb: Unknown memory size!\n");
L
Linus Torvalds 已提交
2325 2326
		mem = 1024 * 1024;
	}
K
Krzysztof Helt 已提交
2327 2328 2329 2330
	if (SRF & 0x80)
	/* If DRAM bank switching is enabled, there must be twice as much
	 * memory installed. (4MB on the 5434)
	 */
L
Linus Torvalds 已提交
2331
		mem *= 2;
K
Krzysztof Helt 已提交
2332

L
Linus Torvalds 已提交
2333 2334
	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */

K
Krzysztof Helt 已提交
2335
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2336 2337 2338
	return mem;
}

K
Krzysztof Helt 已提交
2339 2340
static void get_pci_addrs(const struct pci_dev *pdev,
			  unsigned long *display, unsigned long *registers)
L
Linus Torvalds 已提交
2341
{
K
Krzysztof Helt 已提交
2342 2343 2344
	assert(pdev != NULL);
	assert(display != NULL);
	assert(registers != NULL);
L
Linus Torvalds 已提交
2345

K
Krzysztof Helt 已提交
2346
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360

	*display = 0;
	*registers = 0;

	/* This is a best-guess for now */

	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
		*display = pci_resource_start(pdev, 1);
		*registers = pci_resource_start(pdev, 0);
	} else {
		*display = pci_resource_start(pdev, 0);
		*registers = pci_resource_start(pdev, 1);
	}

K
Krzysztof Helt 已提交
2361
	assert(*display != 0);
L
Linus Torvalds 已提交
2362

K
Krzysztof Helt 已提交
2363
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2364 2365
}

K
Krzysztof Helt 已提交
2366
static void cirrusfb_pci_unmap(struct cirrusfb_info *cinfo)
L
Linus Torvalds 已提交
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381
{
	struct pci_dev *pdev = cinfo->pdev;

	iounmap(cinfo->fbmem);
#if 0 /* if system didn't claim this region, we would... */
	release_mem_region(0xA0000, 65535);
#endif
	if (release_io_ports)
		release_region(0x3C0, 32);
	pci_release_regions(pdev);
	framebuffer_release(cinfo->info);
}
#endif /* CONFIG_PCI */

#ifdef CONFIG_ZORRO
K
Krzysztof Helt 已提交
2382
static void __devexit cirrusfb_zorro_unmap(struct cirrusfb_info *cinfo)
L
Linus Torvalds 已提交
2383 2384 2385 2386 2387
{
	zorro_release_device(cinfo->zdev);

	if (cinfo->btype == BT_PICASSO4) {
		cinfo->regbase -= 0x600000;
K
Krzysztof Helt 已提交
2388 2389
		iounmap((void *)cinfo->regbase);
		iounmap((void *)cinfo->fbmem);
L
Linus Torvalds 已提交
2390 2391
	} else {
		if (zorro_resource_start(cinfo->zdev) > 0x01000000)
K
Krzysztof Helt 已提交
2392
			iounmap((void *)cinfo->fbmem);
L
Linus Torvalds 已提交
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
	}
	framebuffer_release(cinfo->info);
}
#endif /* CONFIG_ZORRO */

static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
{
	struct fb_info *info = cinfo->info;
	struct fb_var_screeninfo *var = &info->var;

	info->par = cinfo;
	info->pseudo_palette = cinfo->pseudo_palette;
	info->flags = FBINFO_DEFAULT
		    | FBINFO_HWACCEL_XPAN
		    | FBINFO_HWACCEL_YPAN
		    | FBINFO_HWACCEL_FILLRECT
		    | FBINFO_HWACCEL_COPYAREA;
	if (noaccel)
		info->flags |= FBINFO_HWACCEL_DISABLED;
	info->fbops = &cirrusfb_ops;
	info->screen_base = cinfo->fbmem;
	if (cinfo->btype == BT_GD5480) {
		if (var->bits_per_pixel == 16)
			info->screen_base += 1 * MB_;
		if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
			info->screen_base += 2 * MB_;
	}

	/* Fill fix common fields */
	strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
		sizeof(info->fix.id));

	/* monochrome: only 1 memory plane */
	/* 8 bit and above: Use whole memory area */
	info->fix.smem_start = cinfo->fbmem_phys;
K
Krzysztof Helt 已提交
2428 2429
	info->fix.smem_len   =
		(var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size;
L
Linus Torvalds 已提交
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451
	info->fix.type       = cinfo->currentmode.type;
	info->fix.type_aux   = 0;
	info->fix.visual     = cinfo->currentmode.visual;
	info->fix.xpanstep   = 1;
	info->fix.ypanstep   = 1;
	info->fix.ywrapstep  = 0;
	info->fix.line_length = cinfo->currentmode.line_length;

	/* FIXME: map region at 0xB8000 if available, fill in here */
	info->fix.mmio_start = cinfo->fbregs_phys;
	info->fix.mmio_len   = 0;
	info->fix.accel = FB_ACCEL_NONE;

	fb_alloc_cmap(&info->cmap, 256, 0);

	return 0;
}

static int cirrusfb_register(struct cirrusfb_info *cinfo)
{
	struct fb_info *info;
	int err;
K
Krzysztof Helt 已提交
2452
	enum cirrus_board btype;
L
Linus Torvalds 已提交
2453

K
Krzysztof Helt 已提交
2454
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2455

K
Krzysztof Helt 已提交
2456 2457
	printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based "
		"graphic boards, v" CIRRUSFB_VERSION "\n");
L
Linus Torvalds 已提交
2458 2459 2460 2461 2462

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

	/* sanity checks */
K
Krzysztof Helt 已提交
2463
	assert(btype != BT_NONE);
L
Linus Torvalds 已提交
2464

K
Krzysztof Helt 已提交
2465
	DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem);
L
Linus Torvalds 已提交
2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483

	/* Make pretend we've set the var so our structures are in a "good" */
	/* state, even though we haven't written the mode to the hw yet...  */
	info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
	info->var.activate = FB_ACTIVATE_NOW;

	err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
	if (err < 0) {
		/* should never happen */
		DPRINTK("choking on default var... umm, no good.\n");
		goto err_unmap_cirrusfb;
	}

	/* set all the vital stuff */
	cirrusfb_set_fbinfo(cinfo);

	err = register_framebuffer(info);
	if (err < 0) {
K
Krzysztof Helt 已提交
2484 2485
		printk(KERN_ERR "cirrusfb: could not register "
			"fb device; err = %d!\n", err);
L
Linus Torvalds 已提交
2486 2487 2488
		goto err_dealloc_cmap;
	}

K
Krzysztof Helt 已提交
2489
	DPRINTK("EXIT, returning 0\n");
L
Linus Torvalds 已提交
2490 2491 2492 2493 2494 2495 2496 2497 2498
	return 0;

err_dealloc_cmap:
	fb_dealloc_cmap(&info->cmap);
err_unmap_cirrusfb:
	cinfo->unmap(cinfo);
	return err;
}

K
Krzysztof Helt 已提交
2499
static void __devexit cirrusfb_cleanup(struct fb_info *info)
L
Linus Torvalds 已提交
2500 2501
{
	struct cirrusfb_info *cinfo = info->par;
K
Krzysztof Helt 已提交
2502
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2503

K
Krzysztof Helt 已提交
2504
	switch_monitor(cinfo, 0);
L
Linus Torvalds 已提交
2505

K
Krzysztof Helt 已提交
2506 2507 2508
	unregister_framebuffer(info);
	fb_dealloc_cmap(&info->cmap);
	printk("Framebuffer unregistered\n");
L
Linus Torvalds 已提交
2509 2510
	cinfo->unmap(cinfo);

K
Krzysztof Helt 已提交
2511
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2512 2513 2514
}

#ifdef CONFIG_PCI
K
Krzysztof Helt 已提交
2515
static int cirrusfb_pci_register(struct pci_dev *pdev,
L
Linus Torvalds 已提交
2516 2517 2518 2519
				  const struct pci_device_id *ent)
{
	struct cirrusfb_info *cinfo;
	struct fb_info *info;
K
Krzysztof Helt 已提交
2520
	enum cirrus_board btype;
L
Linus Torvalds 已提交
2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
	unsigned long board_addr, board_size;
	int ret;

	ret = pci_enable_device(pdev);
	if (ret < 0) {
		printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
		goto err_out;
	}

	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
	if (!info) {
		printk(KERN_ERR "cirrusfb: could not allocate memory\n");
		ret = -ENOMEM;
		goto err_disable;
	}

	cinfo = info->par;
	cinfo->info = info;
	cinfo->pdev = pdev;
K
Krzysztof Helt 已提交
2540
	cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
L
Linus Torvalds 已提交
2541

K
Krzysztof Helt 已提交
2542
	DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
L
Linus Torvalds 已提交
2543
		pdev->resource[0].start, btype);
K
Krzysztof Helt 已提交
2544
	DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start);
L
Linus Torvalds 已提交
2545

K
Krzysztof Helt 已提交
2546 2547
	if (isPReP) {
		pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
L
Linus Torvalds 已提交
2548
#ifdef CONFIG_PPC_PREP
K
Krzysztof Helt 已提交
2549
		get_prep_addrs(&board_addr, &cinfo->fbregs_phys);
L
Linus Torvalds 已提交
2550
#endif
K
Krzysztof Helt 已提交
2551
	/* PReP dies if we ioremap the IO registers, but it works w/out... */
L
Linus Torvalds 已提交
2552 2553
		cinfo->regbase = (char __iomem *) cinfo->fbregs_phys;
	} else {
K
Krzysztof Helt 已提交
2554 2555 2556 2557
		DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n");
		get_pci_addrs(pdev, &board_addr, &cinfo->fbregs_phys);
		/* FIXME: this forces VGA.  alternatives? */
		cinfo->regbase = NULL;
L
Linus Torvalds 已提交
2558 2559
	}

K
Krzysztof Helt 已提交
2560 2561
	DPRINTK("Board address: 0x%lx, register address: 0x%lx\n",
		board_addr, cinfo->fbregs_phys);
L
Linus Torvalds 已提交
2562 2563

	board_size = (btype == BT_GD5480) ?
K
Krzysztof Helt 已提交
2564
		32 * MB_ : cirrusfb_get_memsize(cinfo->regbase);
L
Linus Torvalds 已提交
2565 2566

	ret = pci_request_regions(pdev, "cirrusfb");
K
Krzysztof Helt 已提交
2567 2568 2569
	if (ret < 0) {
		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
		       "abort\n",
L
Linus Torvalds 已提交
2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594
		       board_addr);
		goto err_release_fb;
	}
#if 0 /* if the system didn't claim this region, we would... */
	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
,
		       0xA0000L);
		ret = -EBUSY;
		goto err_release_regions;
	}
#endif
	if (request_region(0x3C0, 32, "cirrusfb"))
		release_io_ports = 1;

	cinfo->fbmem = ioremap(board_addr, board_size);
	if (!cinfo->fbmem) {
		ret = -EIO;
		goto err_release_legacy;
	}

	cinfo->fbmem_phys = board_addr;
	cinfo->size = board_size;
	cinfo->unmap = cirrusfb_pci_unmap;

K
Krzysztof Helt 已提交
2595 2596 2597
	printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ",
		cinfo->size / KB_, board_addr);
	printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n");
L
Linus Torvalds 已提交
2598 2599
	pci_set_drvdata(pdev, info);

2600 2601 2602 2603
	ret = cirrusfb_register(cinfo);
	if (ret)
		iounmap(cinfo->fbmem);
	return ret;
L
Linus Torvalds 已提交
2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619

err_release_legacy:
	if (release_io_ports)
		release_region(0x3C0, 32);
#if 0
	release_mem_region(0xA0000, 65535);
err_release_regions:
#endif
	pci_release_regions(pdev);
err_release_fb:
	framebuffer_release(info);
err_disable:
err_out:
	return ret;
}

K
Krzysztof Helt 已提交
2620
static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
L
Linus Torvalds 已提交
2621 2622
{
	struct fb_info *info = pci_get_drvdata(pdev);
K
Krzysztof Helt 已提交
2623
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2624

K
Krzysztof Helt 已提交
2625
	cirrusfb_cleanup(info);
L
Linus Torvalds 已提交
2626

K
Krzysztof Helt 已提交
2627
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649
}

static struct pci_driver cirrusfb_pci_driver = {
	.name		= "cirrusfb",
	.id_table	= cirrusfb_pci_table,
	.probe		= cirrusfb_pci_register,
	.remove		= __devexit_p(cirrusfb_pci_unregister),
#ifdef CONFIG_PM
#if 0
	.suspend	= cirrusfb_pci_suspend,
	.resume		= cirrusfb_pci_resume,
#endif
#endif
};
#endif /* CONFIG_PCI */

#ifdef CONFIG_ZORRO
static int cirrusfb_zorro_register(struct zorro_dev *z,
				   const struct zorro_device_id *ent)
{
	struct cirrusfb_info *cinfo;
	struct fb_info *info;
K
Krzysztof Helt 已提交
2650
	enum cirrus_board btype;
L
Linus Torvalds 已提交
2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663
	struct zorro_dev *z2 = NULL;
	unsigned long board_addr, board_size, size;
	int ret;

	btype = ent->driver_data;
	if (cirrusfb_zorro_table2[btype].id2)
		z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
	size = cirrusfb_zorro_table2[btype].size;
	printk(KERN_INFO "cirrusfb: %s board detected; ",
	       cirrusfb_board_info[btype].name);

	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
	if (!info) {
K
Krzysztof Helt 已提交
2664
		printk(KERN_ERR "cirrusfb: could not allocate memory\n");
L
Linus Torvalds 已提交
2665 2666 2667 2668 2669 2670 2671 2672
		ret = -ENOMEM;
		goto err_out;
	}

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

K
Krzysztof Helt 已提交
2673 2674 2675
	assert(z > 0);
	assert(z2 >= 0);
	assert(btype != BT_NONE);
L
Linus Torvalds 已提交
2676 2677 2678 2679 2680 2681 2682

	cinfo->zdev = z;
	board_addr = zorro_resource_start(z);
	board_size = zorro_resource_len(z);
	cinfo->size = size;

	if (!zorro_request_device(z, "cirrusfb")) {
K
Krzysztof Helt 已提交
2683 2684
		printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
		       "abort\n",
L
Linus Torvalds 已提交
2685 2686 2687 2688 2689
		       board_addr);
		ret = -EBUSY;
		goto err_release_fb;
	}

K
Krzysztof Helt 已提交
2690
	printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
L
Linus Torvalds 已提交
2691 2692 2693 2694

	ret = -EIO;

	if (btype == BT_PICASSO4) {
K
Krzysztof Helt 已提交
2695
		printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000);
L
Linus Torvalds 已提交
2696 2697 2698 2699 2700

		/* To be precise, for the P4 this is not the */
		/* begin of the board, but the begin of RAM. */
		/* for P4, map in its address space in 2 chunks (### TEST! ) */
		/* (note the ugly hardcoded 16M number) */
K
Krzysztof Helt 已提交
2701
		cinfo->regbase = ioremap(board_addr, 16777216);
L
Linus Torvalds 已提交
2702 2703 2704
		if (!cinfo->regbase)
			goto err_release_region;

K
Krzysztof Helt 已提交
2705 2706
		DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
			cinfo->regbase);
L
Linus Torvalds 已提交
2707 2708 2709 2710
		cinfo->regbase += 0x600000;
		cinfo->fbregs_phys = board_addr + 0x600000;

		cinfo->fbmem_phys = board_addr + 16777216;
K
Krzysztof Helt 已提交
2711
		cinfo->fbmem = ioremap(cinfo->fbmem_phys, 16777216);
L
Linus Torvalds 已提交
2712 2713 2714
		if (!cinfo->fbmem)
			goto err_unmap_regbase;
	} else {
K
Krzysztof Helt 已提交
2715 2716
		printk(KERN_INFO " REG at $%lx\n",
			(unsigned long) z2->resource.start);
L
Linus Torvalds 已提交
2717 2718 2719

		cinfo->fbmem_phys = board_addr;
		if (board_addr > 0x01000000)
K
Krzysztof Helt 已提交
2720
			cinfo->fbmem = ioremap(board_addr, board_size);
L
Linus Torvalds 已提交
2721
		else
K
Krzysztof Helt 已提交
2722
			cinfo->fbmem = (caddr_t) ZTWO_VADDR(board_addr);
L
Linus Torvalds 已提交
2723 2724 2725 2726
		if (!cinfo->fbmem)
			goto err_release_region;

		/* set address for REG area of board */
K
Krzysztof Helt 已提交
2727
		cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
L
Linus Torvalds 已提交
2728 2729
		cinfo->fbregs_phys = z2->resource.start;

K
Krzysztof Helt 已提交
2730 2731
		DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
			cinfo->regbase);
L
Linus Torvalds 已提交
2732 2733 2734
	}
	cinfo->unmap = cirrusfb_zorro_unmap;

K
Krzysztof Helt 已提交
2735
	printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
L
Linus Torvalds 已提交
2736 2737
	zorro_set_drvdata(z, info);

2738 2739 2740 2741 2742 2743 2744 2745 2746
	ret = cirrusfb_register(cinfo);
	if (ret) {
		if (btype == BT_PICASSO4) {
			iounmap(cinfo->fbmem);
			iounmap(cinfo->regbase - 0x600000);
		} else if (board_addr > 0x01000000)
			iounmap(cinfo->fbmem);
	}
	return ret;
L
Linus Torvalds 已提交
2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761

err_unmap_regbase:
	/* Parental advisory: explicit hack */
	iounmap(cinfo->regbase - 0x600000);
err_release_region:
	release_region(board_addr, board_size);
err_release_fb:
	framebuffer_release(info);
err_out:
	return ret;
}

void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
{
	struct fb_info *info = zorro_get_drvdata(z);
K
Krzysztof Helt 已提交
2762
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2763

K
Krzysztof Helt 已提交
2764
	cirrusfb_cleanup(info);
L
Linus Torvalds 已提交
2765

K
Krzysztof Helt 已提交
2766
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789
}

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

static int __init cirrusfb_init(void)
{
	int error = 0;

#ifndef MODULE
	char *option = NULL;

	if (fb_get_options("cirrusfb", &option))
		return -ENODEV;
	cirrusfb_setup(option);
#endif

#ifdef CONFIG_ZORRO
2790
	error |= zorro_register_driver(&cirrusfb_zorro_driver);
L
Linus Torvalds 已提交
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802
#endif
#ifdef CONFIG_PCI
	error |= pci_register_driver(&cirrusfb_pci_driver);
#endif
	return error;
}

#ifndef MODULE
static int __init cirrusfb_setup(char *options) {
	char *this_opt, s[32];
	int i;

K
Krzysztof Helt 已提交
2803
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2804 2805 2806 2807

	if (!options || !*options)
		return 0;

K
Krzysztof Helt 已提交
2808
	while ((this_opt = strsep(&options, ",")) != NULL) {
L
Linus Torvalds 已提交
2809 2810 2811 2812 2813
		if (!*this_opt) continue;

		DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);

		for (i = 0; i < NUM_TOTAL_MODES; i++) {
K
Krzysztof Helt 已提交
2814 2815
			sprintf(s, "mode:%s", cirrusfb_predefined[i].name);
			if (strcmp(this_opt, s) == 0)
L
Linus Torvalds 已提交
2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832
				cirrusfb_def_mode = i;
		}
		if (!strcmp(this_opt, "noaccel"))
			noaccel = 1;
	}
	return 0;
}
#endif

    /*
     *  Modularization
     */

MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
MODULE_LICENSE("GPL");

K
Krzysztof Helt 已提交
2833
static void __exit cirrusfb_exit(void)
L
Linus Torvalds 已提交
2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852
{
#ifdef CONFIG_PCI
	pci_unregister_driver(&cirrusfb_pci_driver);
#endif
#ifdef CONFIG_ZORRO
	zorro_unregister_driver(&cirrusfb_zorro_driver);
#endif
}

module_init(cirrusfb_init);

#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    */
K
Krzysztof Helt 已提交
2853
/* these functions myself.					    */
L
Linus Torvalds 已提交
2854 2855 2856
/**********************************************************************/

/*** WGen() - write into one of the external/general registers ***/
K
Krzysztof Helt 已提交
2857
static void WGen(const struct cirrusfb_info *cinfo,
L
Linus Torvalds 已提交
2858 2859 2860 2861 2862 2863
		  int regnum, unsigned char val)
{
	unsigned long regofs = 0;

	if (cinfo->btype == BT_PICASSO) {
		/* Picasso II specific hack */
K
Krzysztof Helt 已提交
2864 2865
/*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
		  regnum == CL_VSSM2) */
L
Linus Torvalds 已提交
2866 2867 2868 2869
		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
			regofs = 0xfff;
	}

K
Krzysztof Helt 已提交
2870
	vga_w(cinfo->regbase, regofs + regnum, val);
L
Linus Torvalds 已提交
2871 2872 2873
}

/*** RGen() - read out one of the external/general registers ***/
K
Krzysztof Helt 已提交
2874
static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
L
Linus Torvalds 已提交
2875 2876 2877 2878 2879
{
	unsigned long regofs = 0;

	if (cinfo->btype == BT_PICASSO) {
		/* Picasso II specific hack */
K
Krzysztof Helt 已提交
2880 2881
/*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
		  regnum == CL_VSSM2) */
L
Linus Torvalds 已提交
2882 2883 2884 2885
		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
			regofs = 0xfff;
	}

K
Krzysztof Helt 已提交
2886
	return vga_r(cinfo->regbase, regofs + regnum);
L
Linus Torvalds 已提交
2887 2888 2889
}

/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
K
Krzysztof Helt 已提交
2890
static void AttrOn(const struct cirrusfb_info *cinfo)
L
Linus Torvalds 已提交
2891
{
K
Krzysztof Helt 已提交
2892
	assert(cinfo != NULL);
L
Linus Torvalds 已提交
2893

K
Krzysztof Helt 已提交
2894
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
2895

K
Krzysztof Helt 已提交
2896
	if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
L
Linus Torvalds 已提交
2897 2898
		/* if we're just in "write value" mode, write back the */
		/* same value as before to not modify anything */
K
Krzysztof Helt 已提交
2899 2900
		vga_w(cinfo->regbase, VGA_ATT_IW,
		      vga_r(cinfo->regbase, VGA_ATT_R));
L
Linus Torvalds 已提交
2901 2902
	}
	/* turn on video bit */
K
Krzysztof Helt 已提交
2903 2904
/*      vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
	vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
L
Linus Torvalds 已提交
2905 2906

	/* dummy write on Reg0 to be on "write index" mode next time */
K
Krzysztof Helt 已提交
2907
	vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
L
Linus Torvalds 已提交
2908

K
Krzysztof Helt 已提交
2909
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
2910 2911 2912 2913 2914 2915 2916 2917
}

/*** 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
 */
K
Krzysztof Helt 已提交
2918
static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
L
Linus Torvalds 已提交
2919 2920 2921 2922 2923 2924
{
	unsigned char dummy;

	if (cinfo->btype == BT_PICASSO) {
		/* Klaus' hint for correct access to HDR on some boards */
		/* first write 0 to pixel mask (3c6) */
K
Krzysztof Helt 已提交
2925 2926
		WGen(cinfo, VGA_PEL_MSK, 0x00);
		udelay(200);
L
Linus Torvalds 已提交
2927
		/* next read dummy from pixel address (3c8) */
K
Krzysztof Helt 已提交
2928 2929
		dummy = RGen(cinfo, VGA_PEL_IW);
		udelay(200);
L
Linus Torvalds 已提交
2930 2931 2932
	}
	/* now do the usual stuff to access the HDR */

K
Krzysztof Helt 已提交
2933 2934 2935 2936 2937 2938 2939 2940
	dummy = RGen(cinfo, VGA_PEL_MSK);
	udelay(200);
	dummy = RGen(cinfo, VGA_PEL_MSK);
	udelay(200);
	dummy = RGen(cinfo, VGA_PEL_MSK);
	udelay(200);
	dummy = RGen(cinfo, VGA_PEL_MSK);
	udelay(200);
L
Linus Torvalds 已提交
2941

K
Krzysztof Helt 已提交
2942 2943
	WGen(cinfo, VGA_PEL_MSK, val);
	udelay(200);
L
Linus Torvalds 已提交
2944 2945 2946

	if (cinfo->btype == BT_PICASSO) {
		/* now first reset HDR access counter */
K
Krzysztof Helt 已提交
2947 2948
		dummy = RGen(cinfo, VGA_PEL_IW);
		udelay(200);
L
Linus Torvalds 已提交
2949 2950 2951

		/* and at the end, restore the mask value */
		/* ## is this mask always 0xff? */
K
Krzysztof Helt 已提交
2952 2953
		WGen(cinfo, VGA_PEL_MSK, 0xff);
		udelay(200);
L
Linus Torvalds 已提交
2954 2955 2956 2957
	}
}

/*** WSFR() - write to the "special function register" (SFR) ***/
K
Krzysztof Helt 已提交
2958
static void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
L
Linus Torvalds 已提交
2959 2960
{
#ifdef CONFIG_ZORRO
K
Krzysztof Helt 已提交
2961
	assert(cinfo->regbase != NULL);
L
Linus Torvalds 已提交
2962
	cinfo->SFR = val;
K
Krzysztof Helt 已提交
2963
	z_writeb(val, cinfo->regbase + 0x8000);
L
Linus Torvalds 已提交
2964 2965 2966 2967
#endif
}

/* The Picasso has a second register for switching the monitor bit */
K
Krzysztof Helt 已提交
2968
static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
L
Linus Torvalds 已提交
2969 2970 2971 2972
{
#ifdef CONFIG_ZORRO
	/* writing an arbitrary value to this one causes the monitor switcher */
	/* to flip to Amiga display */
K
Krzysztof Helt 已提交
2973
	assert(cinfo->regbase != NULL);
L
Linus Torvalds 已提交
2974
	cinfo->SFR = val;
K
Krzysztof Helt 已提交
2975
	z_writeb(val, cinfo->regbase + 0x9000);
L
Linus Torvalds 已提交
2976 2977 2978 2979
#endif
}

/*** WClut - set CLUT entry (range: 0..63) ***/
K
Krzysztof Helt 已提交
2980
static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
L
Linus Torvalds 已提交
2981 2982 2983 2984 2985
	    unsigned char green, unsigned char blue)
{
	unsigned int data = VGA_PEL_D;

	/* address write mode register is not translated.. */
K
Krzysztof Helt 已提交
2986
	vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
L
Linus Torvalds 已提交
2987 2988 2989 2990 2991 2992

	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
		/* but DAC data register IS, at least for Picasso II */
		if (cinfo->btype == BT_PICASSO)
			data += 0xfff;
K
Krzysztof Helt 已提交
2993 2994 2995
		vga_w(cinfo->regbase, data, red);
		vga_w(cinfo->regbase, data, green);
		vga_w(cinfo->regbase, data, blue);
L
Linus Torvalds 已提交
2996
	} else {
K
Krzysztof Helt 已提交
2997 2998 2999
		vga_w(cinfo->regbase, data, blue);
		vga_w(cinfo->regbase, data, green);
		vga_w(cinfo->regbase, data, red);
L
Linus Torvalds 已提交
3000 3001 3002 3003 3004
	}
}

#if 0
/*** RClut - read CLUT entry (range 0..63) ***/
K
Krzysztof Helt 已提交
3005
static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
L
Linus Torvalds 已提交
3006 3007 3008 3009
	    unsigned char *green, unsigned char *blue)
{
	unsigned int data = VGA_PEL_D;

K
Krzysztof Helt 已提交
3010
	vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
L
Linus Torvalds 已提交
3011 3012 3013 3014 3015

	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
		if (cinfo->btype == BT_PICASSO)
			data += 0xfff;
K
Krzysztof Helt 已提交
3016 3017 3018
		*red = vga_r(cinfo->regbase, data);
		*green = vga_r(cinfo->regbase, data);
		*blue = vga_r(cinfo->regbase, data);
L
Linus Torvalds 已提交
3019
	} else {
K
Krzysztof Helt 已提交
3020 3021 3022
		*blue = vga_r(cinfo->regbase, data);
		*green = vga_r(cinfo->regbase, data);
		*red = vga_r(cinfo->regbase, data);
L
Linus Torvalds 已提交
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033
	}
}
#endif

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

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

/* FIXME: use interrupts instead */
K
Krzysztof Helt 已提交
3034
static void cirrusfb_WaitBLT(u8 __iomem *regbase)
L
Linus Torvalds 已提交
3035 3036
{
	/* now busy-wait until we're done */
K
Krzysztof Helt 已提交
3037
	while (vga_rgfx(regbase, CL_GR31) & 0x08)
L
Linus Torvalds 已提交
3038 3039 3040 3041 3042 3043 3044 3045 3046
		/* do nothing */ ;
}

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

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

K
Krzysztof Helt 已提交
3047 3048 3049 3050 3051
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)
L
Linus Torvalds 已提交
3052 3053 3054 3055 3056
{
	u_short nwidth, nheight;
	u_long nsrc, ndest;
	u_char bltmode;

K
Krzysztof Helt 已提交
3057
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076

	nwidth = width - 1;
	nheight = height - 1;

	bltmode = 0x00;
	/* if source adr < dest addr, do the Blt backwards */
	if (cury <= desty) {
		if (cury == desty) {
			/* if src and dest are on the same line, check x */
			if (curx < destx)
				bltmode |= 0x01;
		} else
			bltmode |= 0x01;
	}
	if (!bltmode) {
		/* standard case: forward blitting */
		nsrc = (cury * line_length) + curx;
		ndest = (desty * line_length) + destx;
	} else {
K
Krzysztof Helt 已提交
3077 3078 3079 3080 3081 3082 3083
		/* this means start addresses are at the end,
		 * counting backwards
		 */
		nsrc = cury * line_length + curx +
			nheight * line_length + nwidth;
		ndest = desty * line_length + destx +
			nheight * line_length + nwidth;
L
Linus Torvalds 已提交
3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098
	}

	/*
	   run-down of registers to be programmed:
	   destination pitch
	   source pitch
	   BLT width/height
	   source start
	   destination start
	   BLT mode
	   BLT ROP
	   VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
	   start/stop
	 */

K
Krzysztof Helt 已提交
3099
	cirrusfb_WaitBLT(regbase);
L
Linus Torvalds 已提交
3100 3101

	/* pitch: set to line_length */
K
Krzysztof Helt 已提交
3102 3103 3104 3105 3106 3107 3108 3109
	/* dest pitch low */
	vga_wgfx(regbase, CL_GR24, line_length & 0xff);
	/* dest pitch hi */
	vga_wgfx(regbase, CL_GR25, line_length >> 8);
	/* source pitch low */
	vga_wgfx(regbase, CL_GR26, line_length & 0xff);
	/* source pitch hi */
	vga_wgfx(regbase, CL_GR27, line_length >> 8);
L
Linus Torvalds 已提交
3110 3111

	/* BLT width: actual number of pixels - 1 */
K
Krzysztof Helt 已提交
3112 3113 3114 3115
	/* BLT width low */
	vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
	/* BLT width hi */
	vga_wgfx(regbase, CL_GR21, nwidth >> 8);
L
Linus Torvalds 已提交
3116 3117

	/* BLT height: actual number of lines -1 */
K
Krzysztof Helt 已提交
3118 3119 3120 3121
	/* BLT height low */
	vga_wgfx(regbase, CL_GR22, nheight & 0xff);
	/* BLT width hi */
	vga_wgfx(regbase, CL_GR23, nheight >> 8);
L
Linus Torvalds 已提交
3122 3123

	/* BLT destination */
K
Krzysztof Helt 已提交
3124 3125 3126 3127 3128 3129
	/* BLT dest low */
	vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
	/* BLT dest mid */
	vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
	/* BLT dest hi */
	vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
L
Linus Torvalds 已提交
3130 3131

	/* BLT source */
K
Krzysztof Helt 已提交
3132 3133 3134 3135 3136 3137
	/* BLT src low */
	vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
	/* BLT src mid */
	vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
	/* BLT src hi */
	vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
L
Linus Torvalds 已提交
3138 3139

	/* BLT mode */
K
Krzysztof Helt 已提交
3140
	vga_wgfx(regbase, CL_GR30, bltmode);	/* BLT mode */
L
Linus Torvalds 已提交
3141 3142

	/* BLT ROP: SrcCopy */
K
Krzysztof Helt 已提交
3143
	vga_wgfx(regbase, CL_GR32, 0x0d);	/* BLT ROP */
L
Linus Torvalds 已提交
3144 3145

	/* and finally: GO! */
K
Krzysztof Helt 已提交
3146
	vga_wgfx(regbase, CL_GR31, 0x02);	/* BLT Start/status */
L
Linus Torvalds 已提交
3147

K
Krzysztof Helt 已提交
3148
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
3149 3150 3151 3152 3153 3154 3155 3156
}

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

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

K
Krzysztof Helt 已提交
3157
static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
L
Linus Torvalds 已提交
3158 3159 3160 3161 3162 3163 3164
		     u_short x, u_short y, u_short width, u_short height,
		     u_char color, u_short line_length)
{
	u_short nwidth, nheight;
	u_long ndest;
	u_char op;

K
Krzysztof Helt 已提交
3165
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
3166 3167 3168 3169 3170 3171

	nwidth = width - 1;
	nheight = height - 1;

	ndest = (y * line_length) + x;

K
Krzysztof Helt 已提交
3172
	cirrusfb_WaitBLT(regbase);
L
Linus Torvalds 已提交
3173 3174

	/* pitch: set to line_length */
K
Krzysztof Helt 已提交
3175 3176 3177 3178
	vga_wgfx(regbase, CL_GR24, line_length & 0xff);	/* dest pitch low */
	vga_wgfx(regbase, CL_GR25, line_length >> 8);	/* dest pitch hi */
	vga_wgfx(regbase, CL_GR26, line_length & 0xff);	/* source pitch low */
	vga_wgfx(regbase, CL_GR27, line_length >> 8);	/* source pitch hi */
L
Linus Torvalds 已提交
3179 3180

	/* BLT width: actual number of pixels - 1 */
K
Krzysztof Helt 已提交
3181 3182
	vga_wgfx(regbase, CL_GR20, nwidth & 0xff);	/* BLT width low */
	vga_wgfx(regbase, CL_GR21, nwidth >> 8);	/* BLT width hi */
L
Linus Torvalds 已提交
3183 3184

	/* BLT height: actual number of lines -1 */
K
Krzysztof Helt 已提交
3185 3186
	vga_wgfx(regbase, CL_GR22, nheight & 0xff);	/* BLT height low */
	vga_wgfx(regbase, CL_GR23, nheight >> 8);	/* BLT width hi */
L
Linus Torvalds 已提交
3187 3188

	/* BLT destination */
K
Krzysztof Helt 已提交
3189 3190 3191 3192 3193 3194
	/* BLT dest low */
	vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
	/* BLT dest mid */
	vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
	/* BLT dest hi */
	vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
L
Linus Torvalds 已提交
3195 3196

	/* BLT source: set to 0 (is a dummy here anyway) */
K
Krzysztof Helt 已提交
3197 3198 3199
	vga_wgfx(regbase, CL_GR2C, 0x00);	/* BLT src low */
	vga_wgfx(regbase, CL_GR2D, 0x00);	/* BLT src mid */
	vga_wgfx(regbase, CL_GR2E, 0x00);	/* BLT src hi */
L
Linus Torvalds 已提交
3200 3201 3202

	/* This is a ColorExpand Blt, using the */
	/* same color for foreground and background */
K
Krzysztof Helt 已提交
3203 3204
	vga_wgfx(regbase, VGA_GFX_SR_VALUE, color);	/* foreground color */
	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color);	/* background color */
L
Linus Torvalds 已提交
3205 3206 3207

	op = 0xc0;
	if (bits_per_pixel == 16) {
K
Krzysztof Helt 已提交
3208 3209
		vga_wgfx(regbase, CL_GR10, color);	/* foreground color */
		vga_wgfx(regbase, CL_GR11, color);	/* background color */
L
Linus Torvalds 已提交
3210 3211 3212
		op = 0x50;
		op = 0xd0;
	} else if (bits_per_pixel == 32) {
K
Krzysztof Helt 已提交
3213 3214 3215 3216 3217 3218
		vga_wgfx(regbase, CL_GR10, color);	/* foreground color */
		vga_wgfx(regbase, CL_GR11, color);	/* background color */
		vga_wgfx(regbase, CL_GR12, color);	/* foreground color */
		vga_wgfx(regbase, CL_GR13, color);	/* background color */
		vga_wgfx(regbase, CL_GR14, 0);	/* foreground color */
		vga_wgfx(regbase, CL_GR15, 0);	/* background color */
L
Linus Torvalds 已提交
3219 3220 3221 3222
		op = 0x50;
		op = 0xf0;
	}
	/* BLT mode: color expand, Enable 8x8 copy (faster?) */
K
Krzysztof Helt 已提交
3223
	vga_wgfx(regbase, CL_GR30, op);	/* BLT mode */
L
Linus Torvalds 已提交
3224 3225

	/* BLT ROP: SrcCopy */
K
Krzysztof Helt 已提交
3226
	vga_wgfx(regbase, CL_GR32, 0x0d);	/* BLT ROP */
L
Linus Torvalds 已提交
3227 3228

	/* and finally: GO! */
K
Krzysztof Helt 已提交
3229
	vga_wgfx(regbase, CL_GR31, 0x02);	/* BLT Start/status */
L
Linus Torvalds 已提交
3230

K
Krzysztof Helt 已提交
3231
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
3232 3233 3234 3235 3236 3237
}

/**************************************************************************
 * bestclock() - determine closest possible clock lower(?) than the
 * desired pixel clock
 **************************************************************************/
K
Krzysztof Helt 已提交
3238
static void bestclock(long freq, long *best, long *nom,
L
Linus Torvalds 已提交
3239 3240 3241 3242
		       long *den, long *div, long maxfreq)
{
	long n, h, d, f;

K
Krzysztof Helt 已提交
3243 3244 3245 3246 3247
	assert(best != NULL);
	assert(nom != NULL);
	assert(den != NULL);
	assert(div != NULL);
	assert(maxfreq > 0);
L
Linus Torvalds 已提交
3248 3249 3250 3251 3252

	*nom = 0;
	*den = 0;
	*div = 0;

K
Krzysztof Helt 已提交
3253
	DPRINTK("ENTER\n");
L
Linus Torvalds 已提交
3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269

	if (freq < 8000)
		freq = 8000;

	if (freq > maxfreq)
		freq = maxfreq;

	*best = 0;
	f = freq * 10;

	for (n = 32; n < 128; n++) {
		d = (143181 * n) / f;
		if ((d >= 7) && (d <= 63)) {
			if (d > 31)
				d = (d / 2) * 2;
			h = (14318 * n) / d;
K
Krzysztof Helt 已提交
3270
			if (abs(h - freq) < abs(*best - freq)) {
L
Linus Torvalds 已提交
3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286
				*best = h;
				*nom = n;
				if (d < 32) {
					*den = d;
					*div = 0;
				} else {
					*den = d / 2;
					*div = 1;
				}
			}
		}
		d = ((143181 * n) + f - 1) / f;
		if ((d >= 7) && (d <= 63)) {
			if (d > 31)
				d = (d / 2) * 2;
			h = (14318 * n) / d;
K
Krzysztof Helt 已提交
3287
			if (abs(h - freq) < abs(*best - freq)) {
L
Linus Torvalds 已提交
3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300
				*best = h;
				*nom = n;
				if (d < 32) {
					*den = d;
					*div = 0;
				} else {
					*den = d / 2;
					*div = 1;
				}
			}
		}
	}

K
Krzysztof Helt 已提交
3301 3302 3303
	DPRINTK("Best possible values for given frequency:\n");
	DPRINTK("	best: %ld kHz  nom: %ld  den: %ld  div: %ld\n",
		freq, *nom, *den, *div);
L
Linus Torvalds 已提交
3304

K
Krzysztof Helt 已提交
3305
	DPRINTK("EXIT\n");
L
Linus Torvalds 已提交
3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
}

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

#ifdef CIRRUSFB_DEBUG

/**
 * cirrusfb_dbg_print_byte
 * @name: name associated with byte value to be displayed
 * @val: byte value to be displayed
 *
 * DESCRIPTION:
 * Display an indented string, along with a hexidecimal byte value, and
 * its decoded bits.  Bits 7 through 0 are listed in left-to-right
 * order.
 */

static
K
Krzysztof Helt 已提交
3329
void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
L
Linus Torvalds 已提交
3330
{
K
Krzysztof Helt 已提交
3331 3332 3333 3334 3335 3336 3337 3338 3339 3340
	DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
		name, val,
		val & 0x80 ? '1' : '0',
		val & 0x40 ? '1' : '0',
		val & 0x20 ? '1' : '0',
		val & 0x10 ? '1' : '0',
		val & 0x08 ? '1' : '0',
		val & 0x04 ? '1' : '0',
		val & 0x02 ? '1' : '0',
		val & 0x01 ? '1' : '0');
L
Linus Torvalds 已提交
3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
}

/**
 * cirrusfb_dbg_print_regs
 * @base: 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
K
Krzysztof Helt 已提交
3355
void cirrusfb_dbg_print_regs(caddr_t regbase,
K
Krzysztof Helt 已提交
3356
			     enum cirrusfb_dbg_reg_class reg_class, ...)
L
Linus Torvalds 已提交
3357 3358 3359 3360 3361 3362
{
	va_list list;
	unsigned char val = 0;
	unsigned reg;
	char *name;

K
Krzysztof Helt 已提交
3363
	va_start(list, reg_class);
L
Linus Torvalds 已提交
3364

K
Krzysztof Helt 已提交
3365
	name = va_arg(list, char *);
L
Linus Torvalds 已提交
3366
	while (name != NULL) {
K
Krzysztof Helt 已提交
3367
		reg = va_arg(list, int);
L
Linus Torvalds 已提交
3368 3369 3370

		switch (reg_class) {
		case CRT:
K
Krzysztof Helt 已提交
3371
			val = vga_rcrt(regbase, (unsigned char) reg);
L
Linus Torvalds 已提交
3372 3373
			break;
		case SEQ:
K
Krzysztof Helt 已提交
3374
			val = vga_rseq(regbase, (unsigned char) reg);
L
Linus Torvalds 已提交
3375 3376 3377
			break;
		default:
			/* should never occur */
3378
			assert(false);
L
Linus Torvalds 已提交
3379 3380 3381
			break;
		}

K
Krzysztof Helt 已提交
3382
		cirrusfb_dbg_print_byte(name, val);
L
Linus Torvalds 已提交
3383

K
Krzysztof Helt 已提交
3384
		name = va_arg(list, char *);
L
Linus Torvalds 已提交
3385 3386
	}

K
Krzysztof Helt 已提交
3387
	va_end(list);
L
Linus Torvalds 已提交
3388 3389 3390 3391 3392 3393 3394 3395 3396
}

/**
 * cirrusfb_dump
 * @cirrusfbinfo:
 *
 * DESCRIPTION:
 */

K
Krzysztof Helt 已提交
3397
static void cirrusfb_dump(void)
L
Linus Torvalds 已提交
3398
{
K
Krzysztof Helt 已提交
3399
	cirrusfb_dbg_reg_dump(NULL);
L
Linus Torvalds 已提交
3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412
}

/**
 * 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
K
Krzysztof Helt 已提交
3413
void cirrusfb_dbg_reg_dump(caddr_t regbase)
L
Linus Torvalds 已提交
3414
{
K
Krzysztof Helt 已提交
3415
	DPRINTK("CIRRUSFB VGA CRTC register dump:\n");
L
Linus Torvalds 已提交
3416

K
Krzysztof Helt 已提交
3417
	cirrusfb_dbg_print_regs(regbase, CRT,
L
Linus Torvalds 已提交
3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466
			   "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);

K
Krzysztof Helt 已提交
3467
	DPRINTK("\n");
L
Linus Torvalds 已提交
3468

K
Krzysztof Helt 已提交
3469
	DPRINTK("CIRRUSFB VGA SEQ register dump:\n");
L
Linus Torvalds 已提交
3470

K
Krzysztof Helt 已提交
3471
	cirrusfb_dbg_print_regs(regbase, SEQ,
L
Linus Torvalds 已提交
3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499
			   "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);

K
Krzysztof Helt 已提交
3500
	DPRINTK("\n");
L
Linus Torvalds 已提交
3501 3502 3503 3504
}

#endif				/* CIRRUSFB_DEBUG */