1/*
2 * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
3 *
4 * Copyright 1999-2001 Jeff Garzik <jgarzik@mandrakesoft.com>
5 *
6 * Contributors (thanks, all!)
7 *
8 *      Jeff Rugen:
9 *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
10 *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
11 *
12 *	Geert Uytterhoeven:
13 *	Excellent code review.
14 *
15 *	Lars Hecking:
16 *	Amiga updates and testing.
17 *
18 * Original clgenfb author:  Frank Neumann
19 *
20 * Based on retz3fb.c and clgen.c:
21 *      Copyright (C) 1997 Jes Sorensen
22 *      Copyright (C) 1996 Frank Neumann
23 *
24 ***************************************************************
25 *
26 * Format this code with GNU indent '-kr -i8 -pcs' options.
27 *
28 * This file is subject to the terms and conditions of the GNU General Public
29 * License.  See the file COPYING in the main directory of this archive
30 * for more details.
31 *
32 */
33
34#define CLGEN_VERSION "1.9.9.1"
35
36#include <linux/config.h>
37#include <linux/module.h>
38#include <linux/kernel.h>
39#include <linux/errno.h>
40#include <linux/string.h>
41#include <linux/mm.h>
42#include <linux/tty.h>
43#include <linux/slab.h>
44#include <linux/delay.h>
45#include <linux/fb.h>
46#include <linux/init.h>
47#include <linux/selection.h>
48#include <asm/pgtable.h>
49
50#ifdef CONFIG_ZORRO
51#include <linux/zorro.h>
52#endif
53#ifdef CONFIG_PCI
54#include <linux/pci.h>
55#endif
56#ifdef CONFIG_AMIGA
57#include <asm/amigahw.h>
58#endif
59#ifdef CONFIG_ALL_PPC
60#include <asm/processor.h>
61#define isPReP (_machine == _MACH_prep)
62#else
63#define isPReP 0
64#endif
65
66#include <video/fbcon.h>
67#include <video/fbcon-mfb.h>
68#include <video/fbcon-cfb8.h>
69#include <video/fbcon-cfb16.h>
70#include <video/fbcon-cfb24.h>
71#include <video/fbcon-cfb32.h>
72
73#include "clgenfb.h"
74#include "vga.h"
75
76
77/*****************************************************************
78 *
79 * debugging and utility macros
80 *
81 */
82
83/* enable debug output? */
84/* #define CLGEN_DEBUG 1 */
85
86/* disable runtime assertions? */
87/* #define CLGEN_NDEBUG */
88
89/* debug output */
90#ifdef CLGEN_DEBUG
91#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
92#else
93#define DPRINTK(fmt, args...)
94#endif
95
96/* debugging assertions */
97#ifndef CLGEN_NDEBUG
98#define assert(expr) \
99        if(!(expr)) { \
100        printk( "Assertion failed! %s,%s,%s,line=%d\n",\
101        #expr,__FILE__,__FUNCTION__,__LINE__); \
102        }
103#else
104#define assert(expr)
105#endif
106
107#ifdef TRUE
108#undef TRUE
109#endif
110#ifdef FALSE
111#undef FALSE
112#endif
113#define TRUE  1
114#define FALSE 0
115
116#define MB_ (1024*1024)
117#define KB_ (1024)
118
119#define MAX_NUM_BOARDS 7
120
121
122/*****************************************************************
123 *
124 * chipset information
125 *
126 */
127
128/* board types */
129typedef enum {
130	BT_NONE = 0,
131	BT_SD64,
132	BT_PICCOLO,
133	BT_PICASSO,
134	BT_SPECTRUM,
135	BT_PICASSO4,	/* GD5446 */
136	BT_ALPINE,	/* GD543x/4x */
137	BT_GD5480,
138	BT_LAGUNA,	/* GD546x */
139} clgen_board_t;
140
141
142/*
143 * per-board-type information, used for enumerating and abstracting
144 * chip-specific information
145 * NOTE: MUST be in the same order as clgen_board_t in order to
146 * use direct indexing on this array
147 * NOTE: '__initdata' cannot be used as some of this info
148 * is required at runtime.  Maybe separate into an init-only and
149 * a run-time table?
150 */
151static const struct clgen_board_info_rec {
152	clgen_board_t btype;	/* chipset enum, not strictly necessary, as
153				 * clgen_board_info[] is directly indexed
154				 * by this value */
155	char *name;		/* ASCII name of chipset */
156	long maxclock;		/* maximum video clock */
157	unsigned init_sr07 : 1;	/* init SR07 during init_vgachip() */
158	unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
159	unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
160
161	/* initial SR07 value, then for each mode */
162	unsigned char sr07;
163	unsigned char sr07_1bpp;
164	unsigned char sr07_1bpp_mux;
165	unsigned char sr07_8bpp;
166	unsigned char sr07_8bpp_mux;
167
168	unsigned char sr1f;	/* SR1F VGA initial register value */
169} clgen_board_info[] = {
170	{ BT_NONE, }, /* dummy record */
171	{ BT_SD64,
172		"CL SD64",
173		140000,		/* the SD64/P4 have a higher max. videoclock */
174		TRUE,
175		TRUE,
176		TRUE,
177		0xF0,
178		0xF0,
179		0,		/* unused, does not multiplex */
180		0xF1,
181		0,		/* unused, does not multiplex */
182		0x20 },
183	{ BT_PICCOLO,
184		"CL Piccolo",
185		90000,
186		TRUE,
187		TRUE,
188		FALSE,
189		0x80,
190		0x80,
191		0,		/* unused, does not multiplex */
192		0x81,
193		0,		/* unused, does not multiplex */
194		0x22 },
195	{ BT_PICASSO,
196		"CL Picasso",
197		90000,
198		TRUE,
199		TRUE,
200		FALSE,
201		0x20,
202		0x20,
203		0,		/* unused, does not multiplex */
204		0x21,
205		0,		/* unused, does not multiplex */
206		0x22 },
207	{ BT_SPECTRUM,
208		"CL Spectrum",
209		90000,
210		TRUE,
211		TRUE,
212		FALSE,
213		0x80,
214		0x80,
215		0,		/* unused, does not multiplex */
216		0x81,
217		0,		/* unused, does not multiplex */
218		0x22 },
219	{ BT_PICASSO4,
220		"CL Picasso4",
221		140000,		/* the SD64/P4 have a higher max. videoclock */
222		TRUE,
223		FALSE,
224		TRUE,
225		0x20,
226		0x20,
227		0,		/* unused, does not multiplex */
228		0x21,
229		0,		/* unused, does not multiplex */
230		0 },
231	{ BT_ALPINE,
232		"CL Alpine",
233		110000,		/* 135100 for some, 85500 for others */
234		TRUE,
235		TRUE,
236		TRUE,
237		0xA0,
238		0xA1,
239		0xA7,
240		0xA1,
241		0xA7,
242		0x1C },
243	{ BT_GD5480,
244		"CL GD5480",
245		90000,
246		TRUE,
247		TRUE,
248		TRUE,
249		0x10,
250		0x11,
251		0,		/* unused, does not multiplex */
252		0x11,
253		0,		/* unused, does not multiplex */
254		0x1C },
255	{ BT_LAGUNA,
256		"CL Laguna",
257		135100,
258		FALSE,
259		FALSE,
260		TRUE,
261		0,		/* unused */
262		0,		/* unused */
263		0,		/* unused */
264		0,		/* unused */
265		0,		/* unused */
266		0 },		/* unused */
267};
268
269
270#ifdef CONFIG_PCI
271/* the list of PCI devices for which we probe, and the
272 * order in which we do it */
273static const struct {
274	clgen_board_t btype;
275	const char *nameOverride;
276	unsigned short device;
277} clgen_pci_probe_list[] __initdata = {
278	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5436 },
279	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_8 },
280	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
281	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
282	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 },
283	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7548 },
284	{ BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
285	{ BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
286	{ BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
287	{ BT_LAGUNA, "CL Laguna 3D", PCI_DEVICE_ID_CIRRUS_5464 },
288	{ BT_LAGUNA, "CL Laguna 3DA", PCI_DEVICE_ID_CIRRUS_5465 },
289};
290#endif /* CONFIG_PCI */
291
292
293#ifdef CONFIG_ZORRO
294static const struct {
295	clgen_board_t btype;
296	zorro_id id, id2;
297	unsigned long size;
298} clgen_zorro_probe_list[] __initdata = {
299	{ BT_SD64,
300		ZORRO_PROD_HELFRICH_SD64_RAM,
301		ZORRO_PROD_HELFRICH_SD64_REG,
302		0x400000 },
303	{ BT_PICCOLO,
304		ZORRO_PROD_HELFRICH_PICCOLO_RAM,
305		ZORRO_PROD_HELFRICH_PICCOLO_REG,
306		0x200000 },
307	{ BT_PICASSO,
308		ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
309		ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
310		0x200000 },
311	{ BT_SPECTRUM,
312		ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
313		ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
314		0x200000 },
315	{ BT_PICASSO4,
316		ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
317		0,
318		0x400000 },
319};
320#endif /* CONFIG_ZORRO */
321
322
323
324struct clgenfb_par {
325	struct fb_var_screeninfo var;
326
327	__u32 line_length;	/* in BYTES! */
328	__u32 visual;
329	__u32 type;
330
331	long freq;
332	long nom;
333	long den;
334	long div;
335	long multiplexing;
336	long mclk;
337	long divMCLK;
338
339	long HorizRes;		/* The x resolution in pixel */
340	long HorizTotal;
341	long HorizDispEnd;
342	long HorizBlankStart;
343	long HorizBlankEnd;
344	long HorizSyncStart;
345	long HorizSyncEnd;
346
347	long VertRes;		/* the physical y resolution in scanlines */
348	long VertTotal;
349	long VertDispEnd;
350	long VertSyncStart;
351	long VertSyncEnd;
352	long VertBlankStart;
353	long VertBlankEnd;
354};
355
356
357
358#ifdef CLGEN_DEBUG
359typedef enum {
360        CRT,
361        SEQ
362} clgen_dbg_reg_class_t;
363#endif                          /* CLGEN_DEBUG */
364
365
366
367
368/* info about board */
369struct clgenfb_info {
370	struct fb_info_gen gen;
371
372	caddr_t fbmem;
373	caddr_t regs;
374	caddr_t mem;
375	unsigned long size;
376	clgen_board_t btype;
377	int smallboard;
378	unsigned char SFR;	/* Shadow of special function register */
379
380	unsigned long fbmem_phys;
381	unsigned long fbregs_phys;
382
383	struct clgenfb_par currentmode;
384
385	struct { u8 red, green, blue, pad; } palette[256];
386
387	union {
388#ifdef FBCON_HAS_CFB16
389		u16 cfb16[16];
390#endif
391#ifdef FBCON_HAS_CFB24
392		u32 cfb24[16];
393#endif
394#ifdef FBCON_HAS_CFB32
395		u32 cfb32[16];
396#endif
397	} fbcon_cmap;
398
399#ifdef CONFIG_ZORRO
400	unsigned long board_addr,
401		      board_size;
402#endif
403
404#ifdef CONFIG_PCI
405	struct pci_dev *pdev;
406#endif
407};
408
409
410
411
412static struct display disp;
413
414static struct clgenfb_info boards[MAX_NUM_BOARDS];	/* the boards */
415
416static unsigned clgen_def_mode = 1;
417static int noaccel = 0;
418
419
420
421/*
422 *    Predefined Video Modes
423 */
424
425static const struct {
426	const char *name;
427	struct fb_var_screeninfo var;
428} clgenfb_predefined[] __initdata =
429
430{
431	{"Autodetect",		/* autodetect mode */
432	 {0}
433	},
434
435	{"640x480",		/* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
436	 {
437		 640, 480, 640, 480, 0, 0, 8, 0,
438		 {0, 8, 0},
439		 {0, 8, 0},
440		 {0, 8, 0},
441		 {0, 0, 0},
442	       0, 0, -1, -1, FB_ACCEL_NONE, 40000, 48, 16, 32, 8, 96, 4,
443     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
444	 }
445	},
446
447	{"800x600",		/* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
448	 {
449		 800, 600, 800, 600, 0, 0, 8, 0,
450		 {0, 8, 0},
451		 {0, 8, 0},
452		 {0, 8, 0},
453		 {0, 0, 0},
454	       0, 0, -1, -1, FB_ACCEL_NONE, 20000, 128, 16, 24, 2, 96, 6,
455     0, FB_VMODE_NONINTERLACED
456	 }
457	},
458
459	/*
460	   Modeline from XF86Config:
461	   Mode "1024x768" 80  1024 1136 1340 1432  768 770 774 805
462	 */
463	{"1024x768",		/* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
464		{
465			1024, 768, 1024, 768, 0, 0, 8, 0,
466			{0, 8, 0},
467			{0, 8, 0},
468			{0, 8, 0},
469			{0, 0, 0},
470	      0, 0, -1, -1, FB_ACCEL_NONE, 12500, 144, 32, 30, 2, 192, 6,
471     0, FB_VMODE_NONINTERLACED
472		}
473	}
474};
475
476#define NUM_TOTAL_MODES    ARRAY_SIZE(clgenfb_predefined)
477static struct fb_var_screeninfo clgenfb_default;
478
479/*
480 *    Frame Buffer Name
481 */
482
483static const char *clgenfb_name = "CLgen";
484
485/****************************************************************************/
486/**** BEGIN PROTOTYPES ******************************************************/
487
488
489/*--- Interface used by the world ------------------------------------------*/
490int clgenfb_init (void);
491int clgenfb_setup (char *options);
492
493static int clgenfb_open (struct fb_info *info, int user);
494static int clgenfb_release (struct fb_info *info, int user);
495
496/* function table of the above functions */
497static struct fb_ops clgenfb_ops = {
498	owner:		THIS_MODULE,
499	fb_open:	clgenfb_open,
500	fb_release:	clgenfb_release,
501	fb_get_fix:	fbgen_get_fix,
502	fb_get_var:	fbgen_get_var,
503	fb_set_var:	fbgen_set_var,
504	fb_get_cmap:	fbgen_get_cmap,
505	fb_set_cmap:	fbgen_set_cmap,
506	fb_pan_display:	fbgen_pan_display,
507};
508
509/*--- Hardware Specific Routines -------------------------------------------*/
510static void clgen_detect (void);
511static int clgen_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
512			     struct fb_info_gen *info);
513static int clgen_decode_var (const struct fb_var_screeninfo *var, void *par,
514			     struct fb_info_gen *info);
515static int clgen_encode_var (struct fb_var_screeninfo *var, const void *par,
516			     struct fb_info_gen *info);
517static void clgen_get_par (void *par, struct fb_info_gen *info);
518static void clgen_set_par (const void *par, struct fb_info_gen *info);
519static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green,
520			    unsigned *blue, unsigned *transp,
521			    struct fb_info *info);
522static int clgen_setcolreg (unsigned regno, unsigned red, unsigned green,
523			    unsigned blue, unsigned transp,
524			    struct fb_info *info);
525static int clgen_pan_display (const struct fb_var_screeninfo *var,
526			      struct fb_info_gen *info);
527static int clgen_blank (int blank_mode, struct fb_info_gen *info);
528
529static void clgen_set_disp (const void *par, struct display *disp,
530			    struct fb_info_gen *info);
531
532/* function table of the above functions */
533static struct fbgen_hwswitch clgen_hwswitch =
534{
535	clgen_detect,
536	clgen_encode_fix,
537	clgen_decode_var,
538	clgen_encode_var,
539	clgen_get_par,
540	clgen_set_par,
541	clgen_getcolreg,
542	clgen_setcolreg,
543	clgen_pan_display,
544	clgen_blank,
545	clgen_set_disp
546};
547
548/* Text console acceleration */
549
550#ifdef FBCON_HAS_CFB8
551static void fbcon_clgen8_bmove (struct display *p, int sy, int sx,
552				int dy, int dx, int height, int width);
553static void fbcon_clgen8_clear (struct vc_data *conp, struct display *p,
554				int sy, int sx, int height, int width);
555
556static struct display_switch fbcon_clgen_8 = {
557	setup:		fbcon_cfb8_setup,
558	bmove:		fbcon_clgen8_bmove,
559	clear:		fbcon_clgen8_clear,
560	putc:		fbcon_cfb8_putc,
561	putcs:		fbcon_cfb8_putcs,
562	revc:		fbcon_cfb8_revc,
563	clear_margins:	fbcon_cfb8_clear_margins,
564	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
565};
566#endif
567#ifdef FBCON_HAS_CFB16
568static void fbcon_clgen16_bmove (struct display *p, int sy, int sx,
569				 int dy, int dx, int height, int width);
570static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
571				 int sy, int sx, int height, int width);
572static struct display_switch fbcon_clgen_16 = {
573	setup:		fbcon_cfb16_setup,
574	bmove:		fbcon_clgen16_bmove,
575	clear:		fbcon_clgen16_clear,
576	putc:		fbcon_cfb16_putc,
577	putcs:		fbcon_cfb16_putcs,
578	revc:		fbcon_cfb16_revc,
579	clear_margins:	fbcon_cfb16_clear_margins,
580	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
581};
582#endif
583#ifdef FBCON_HAS_CFB32
584static void fbcon_clgen32_bmove (struct display *p, int sy, int sx,
585				 int dy, int dx, int height, int width);
586static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
587				 int sy, int sx, int height, int width);
588static struct display_switch fbcon_clgen_32 = {
589	setup:		fbcon_cfb32_setup,
590	bmove:		fbcon_clgen32_bmove,
591	clear:		fbcon_clgen32_clear,
592	putc:		fbcon_cfb32_putc,
593	putcs:		fbcon_cfb32_putcs,
594	revc:		fbcon_cfb32_revc,
595	clear_margins:	fbcon_cfb32_clear_margins,
596	fontwidthmask:	FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
597};
598#endif
599
600
601
602/*--- Internal routines ----------------------------------------------------*/
603static void init_vgachip (struct clgenfb_info *fb_info);
604static void switch_monitor (struct clgenfb_info *fb_info, int on);
605static void WGen (const struct clgenfb_info *fb_info,
606		  int regnum, unsigned char val);
607static unsigned char RGen (const struct clgenfb_info *fb_info, int regnum);
608static void AttrOn (const struct clgenfb_info *fb_info);
609static void WHDR (const struct clgenfb_info *fb_info, unsigned char val);
610static void WSFR (struct clgenfb_info *fb_info, unsigned char val);
611static void WSFR2 (struct clgenfb_info *fb_info, unsigned char val);
612static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
613		   unsigned char green,
614		   unsigned char blue);
615static void clgen_WaitBLT (caddr_t regbase);
616static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury,
617			  u_short destx, u_short desty,
618			  u_short width, u_short height,
619			  u_short line_length);
620static void clgen_RectFill (struct clgenfb_info *fb_info, u_short x, u_short y,
621			    u_short width, u_short height,
622			    u_char color, u_short line_length);
623
624static void bestclock (long freq, long *best,
625		       long *nom, long *den,
626		       long *div, long maxfreq);
627
628#ifdef CLGEN_DEBUG
629static void clgen_dump (void);
630static void clgen_dbg_reg_dump (caddr_t regbase);
631static void clgen_dbg_print_regs (caddr_t regbase, clgen_dbg_reg_class_t reg_class,...);
632static void clgen_dbg_print_byte (const char *name, unsigned char val);
633#endif /* CLGEN_DEBUG */
634
635/*** END   PROTOTYPES ********************************************************/
636/*****************************************************************************/
637/*** BEGIN Interface Used by the World ***************************************/
638
639static int opencount = 0;
640
641/*--- Open /dev/fbx ---------------------------------------------------------*/
642static int clgenfb_open (struct fb_info *info, int user)
643{
644	if (opencount++ == 0)
645		switch_monitor ((struct clgenfb_info *) info, 1);
646	return 0;
647}
648
649/*--- Close /dev/fbx --------------------------------------------------------*/
650static int clgenfb_release (struct fb_info *info, int user)
651{
652	if (--opencount == 0)
653		switch_monitor ((struct clgenfb_info *) info, 0);
654	return 0;
655}
656
657/**** END   Interface used by the World *************************************/
658/****************************************************************************/
659/**** BEGIN Hardware specific Routines **************************************/
660
661static void clgen_detect (void)
662{
663	DPRINTK ("ENTER\n");
664	DPRINTK ("EXIT\n");
665}
666
667static int clgen_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
668			     struct fb_info_gen *info)
669{
670	struct clgenfb_par *_par = (struct clgenfb_par *) par;
671	struct clgenfb_info *_info = (struct clgenfb_info *) info;
672
673	DPRINTK ("ENTER\n");
674
675	memset (fix, 0, sizeof (struct fb_fix_screeninfo));
676	strcpy (fix->id, clgenfb_name);
677
678	if (_info->btype == BT_GD5480) {
679		/* Select proper byte-swapping aperture */
680		switch (_par->var.bits_per_pixel) {
681		case 1:
682		case 8:
683			fix->smem_start = _info->fbmem_phys;
684			break;
685		case 16:
686			fix->smem_start = _info->fbmem_phys + 1 * MB_;
687			break;
688		case 24:
689		case 32:
690			fix->smem_start = _info->fbmem_phys + 2 * MB_;
691			break;
692		}
693	} else {
694		fix->smem_start = _info->fbmem_phys;
695	}
696
697	/* monochrome: only 1 memory plane */
698	/* 8 bit and above: Use whole memory area */
699	fix->smem_len = _par->var.bits_per_pixel == 1 ? _info->size / 4
700	    : _info->size;
701	fix->type = _par->type;
702	fix->type_aux = 0;
703	fix->visual = _par->visual;
704	fix->xpanstep = 1;
705	fix->ypanstep = 1;
706	fix->ywrapstep = 0;
707	fix->line_length = _par->line_length;
708
709	fix->mmio_start = 0;
710	fix->mmio_len = 0;
711	fix->accel = FB_ACCEL_NONE;
712
713	DPRINTK ("EXIT\n");
714	return 0;
715}
716
717
718
719/* Get a good MCLK value */
720static long clgen_get_mclk (long freq, int bpp, long *div)
721{
722	long mclk;
723
724	assert (div != NULL);
725
726	/* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
727	 * Assume a 64-bit data path for now.  The formula is:
728	 * ((B * PCLK * 2)/W) * 1.2
729	 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
730	mclk = ((bpp / 8) * freq * 2) / 4;
731	mclk = (mclk * 12) / 10;
732	if (mclk < 50000)
733		mclk = 50000;
734	DPRINTK ("Use MCLK of %ld kHz\n", mclk);
735
736	/* Calculate value for SR1F.  Multiply by 2 so we can round up. */
737	mclk = ((mclk * 16) / 14318);
738	mclk = (mclk + 1) / 2;
739	DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
740
741	/* Determine if we should use MCLK instead of VCLK, and if so, what we
742	   * should divide it by to get VCLK */
743	switch (freq) {
744	case 24751 ... 25249:
745		*div = 2;
746		DPRINTK ("Using VCLK = MCLK/2\n");
747		break;
748	case 49501 ... 50499:
749		*div = 1;
750		DPRINTK ("Using VCLK = MCLK\n");
751		break;
752	default:
753		*div = 0;
754		break;
755	}
756
757	return mclk;
758}
759
760static int clgen_decode_var (const struct fb_var_screeninfo *var, void *par,
761			     struct fb_info_gen *info)
762{
763	long freq;
764	long maxclock;
765	int xres, hfront, hsync, hback;
766	int yres, vfront, vsync, vback;
767	int nom, den;		/* translyting from pixels->bytes */
768	int i;
769	static struct {
770		int xres, yres;
771	} modes[] = { {
772			1600, 1280
773	}, {
774		1280, 1024
775	}, {
776		1024, 768
777	},
778	{
779		800, 600
780	}, {
781		640, 480
782	}, {
783		-1, -1
784	}
785	};
786
787	struct clgenfb_par *_par = (struct clgenfb_par *) par;
788	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
789
790	assert (var != NULL);
791	assert (par != NULL);
792	assert (info != NULL);
793
794	DPRINTK ("ENTER\n");
795
796	DPRINTK ("Requested: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel);
797	DPRINTK ("  virtual: %dx%d\n", var->xres_virtual, var->yres_virtual);
798	DPRINTK ("   offset: (%d,%d)\n", var->xoffset, var->yoffset);
799	DPRINTK ("grayscale: %d\n", var->grayscale);
800
801	memset (par, 0, sizeof (struct clgenfb_par));
802
803	_par->var = *var;
804
805	switch (var->bits_per_pixel) {
806	case 1:
807		nom = 4;
808		den = 8;
809		break;		/* 8 pixel per byte, only 1/4th of mem usable */
810	case 2 ... 8:
811		_par->var.bits_per_pixel = 8;
812		nom = 1;
813		den = 1;
814		break;		/* 1 pixel == 1 byte */
815	case 9 ... 16:
816		_par->var.bits_per_pixel = 16;
817		nom = 2;
818		den = 1;
819		break;		/* 2 bytes per pixel */
820	case 17 ... 24:
821		_par->var.bits_per_pixel = 24;
822		nom = 3;
823		den = 1;
824		break;		/* 3 bytes per pixel */
825	case 25 ... 32:
826		_par->var.bits_per_pixel = 32;
827		nom = 4;
828		den = 1;
829		break;		/* 4 bytes per pixel */
830	default:
831		printk ("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
832			var->xres, var->yres, var->bits_per_pixel);
833		DPRINTK ("EXIT - EINVAL error\n");
834		return -EINVAL;
835	}
836
837	if (_par->var.xres * nom / den * _par->var.yres > fb_info->size) {
838		printk ("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
839			var->xres, var->yres, var->bits_per_pixel);
840		DPRINTK ("EXIT - EINVAL error\n");
841		return -EINVAL;
842	}
843	/* use highest possible virtual resolution */
844	if (_par->var.xres_virtual == -1 &&
845	    _par->var.yres_virtual == -1) {
846		printk ("clgen: using maximum available virtual resolution\n");
847		for (i = 0; modes[i].xres != -1; i++) {
848			if (modes[i].xres * nom / den * modes[i].yres < fb_info->size / 2)
849				break;
850		}
851		if (modes[i].xres == -1) {
852			printk ("clgen: could not find a virtual resolution that fits into video memory!!\n");
853			DPRINTK ("EXIT - EINVAL error\n");
854			return -EINVAL;
855		}
856		_par->var.xres_virtual = modes[i].xres;
857		_par->var.yres_virtual = modes[i].yres;
858
859		printk ("clgen: virtual resolution set to maximum of %dx%d\n",
860			_par->var.xres_virtual, _par->var.yres_virtual);
861	} else if (_par->var.xres_virtual == -1) {
862	} else if (_par->var.yres_virtual == -1) {
863	}
864	if (_par->var.xoffset < 0)
865		_par->var.xoffset = 0;
866	if (_par->var.yoffset < 0)
867		_par->var.yoffset = 0;
868
869	/* truncate xoffset and yoffset to maximum if too high */
870	if (_par->var.xoffset > _par->var.xres_virtual - _par->var.xres)
871		_par->var.xoffset = _par->var.xres_virtual - _par->var.xres - 1;
872
873	if (_par->var.yoffset > _par->var.yres_virtual - _par->var.yres)
874		_par->var.yoffset = _par->var.yres_virtual - _par->var.yres - 1;
875
876	switch (_par->var.bits_per_pixel) {
877	case 1:
878		_par->line_length = _par->var.xres_virtual / 8;
879		_par->visual = FB_VISUAL_MONO10;
880		break;
881
882	case 8:
883		_par->line_length = _par->var.xres_virtual;
884		_par->visual = FB_VISUAL_PSEUDOCOLOR;
885		_par->var.red.offset = 0;
886		_par->var.red.length = 6;
887		_par->var.green.offset = 0;
888		_par->var.green.length = 6;
889		_par->var.blue.offset = 0;
890		_par->var.blue.length = 6;
891		break;
892
893	case 16:
894		_par->line_length = _par->var.xres_virtual * 2;
895		_par->visual = FB_VISUAL_DIRECTCOLOR;
896		if(isPReP) {
897			_par->var.red.offset = 2;
898			_par->var.green.offset = -3;
899			_par->var.blue.offset = 8;
900		} else {
901			_par->var.red.offset = 10;
902			_par->var.green.offset = 5;
903			_par->var.blue.offset = 0;
904		}
905		_par->var.red.length = 5;
906		_par->var.green.length = 5;
907		_par->var.blue.length = 5;
908		break;
909
910	case 24:
911		_par->line_length = _par->var.xres_virtual * 3;
912		_par->visual = FB_VISUAL_DIRECTCOLOR;
913		if(isPReP) {
914			_par->var.red.offset = 8;
915			_par->var.green.offset = 16;
916			_par->var.blue.offset = 24;
917		} else {
918			_par->var.red.offset = 16;
919			_par->var.green.offset = 8;
920			_par->var.blue.offset = 0;
921		}
922		_par->var.red.length = 8;
923		_par->var.green.length = 8;
924		_par->var.blue.length = 8;
925		break;
926
927	case 32:
928		_par->line_length = _par->var.xres_virtual * 4;
929		_par->visual = FB_VISUAL_DIRECTCOLOR;
930		if(isPReP) {
931			_par->var.red.offset = 8;
932			_par->var.green.offset = 16;
933			_par->var.blue.offset = 24;
934		} else {
935			_par->var.red.offset = 16;
936			_par->var.green.offset = 8;
937			_par->var.blue.offset = 0;
938		}
939		_par->var.red.length = 8;
940		_par->var.green.length = 8;
941		_par->var.blue.length = 8;
942		break;
943
944	default:
945		DPRINTK("Unsupported bpp size: %d\n", _par->var.bits_per_pixel);
946		assert (FALSE);
947		/* should never occur */
948		break;
949	}
950
951	_par->var.red.msb_right =
952	    _par->var.green.msb_right =
953	    _par->var.blue.msb_right =
954	    _par->var.transp.offset =
955	    _par->var.transp.length =
956	    _par->var.transp.msb_right = 0;
957
958	_par->type = FB_TYPE_PACKED_PIXELS;
959
960	/* convert from ps to kHz */
961	freq = 1000000000 / var->pixclock;
962
963	DPRINTK ("desired pixclock: %ld kHz\n", freq);
964
965	maxclock = clgen_board_info[fb_info->btype].maxclock;
966	_par->multiplexing = 0;
967
968	/* If the frequency is greater than we can support, we might be able
969	 * to use multiplexing for the video mode */
970	if (freq > maxclock) {
971		switch (fb_info->btype) {
972		case BT_ALPINE:
973		case BT_GD5480:
974			_par->multiplexing = 1;
975			break;
976
977		default:
978			printk (KERN_WARNING "clgen: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
979			DPRINTK ("EXIT - return -EINVAL\n");
980			return -EINVAL;
981		}
982	}
983
984	bestclock (freq, &_par->freq, &_par->nom, &_par->den, &_par->div,
985		   maxclock);
986	_par->mclk = clgen_get_mclk (freq, _par->var.bits_per_pixel, &_par->divMCLK);
987
988	xres = _par->var.xres;
989	hfront = _par->var.right_margin;
990	hsync = _par->var.hsync_len;
991	hback = _par->var.left_margin;
992
993	yres = _par->var.yres;
994	vfront = _par->var.lower_margin;
995	vsync = _par->var.vsync_len;
996	vback = _par->var.upper_margin;
997
998	if (_par->var.vmode & FB_VMODE_DOUBLE) {
999		yres *= 2;
1000		vfront *= 2;
1001		vsync *= 2;
1002		vback *= 2;
1003	} else if (_par->var.vmode & FB_VMODE_INTERLACED) {
1004		yres = (yres + 1) / 2;
1005		vfront = (vfront + 1) / 2;
1006		vsync = (vsync + 1) / 2;
1007		vback = (vback + 1) / 2;
1008	}
1009	_par->HorizRes = xres;
1010	_par->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
1011	_par->HorizDispEnd = xres / 8 - 1;
1012	_par->HorizBlankStart = xres / 8;
1013	_par->HorizBlankEnd = _par->HorizTotal + 5;	/* does not count with "-5" */
1014	_par->HorizSyncStart = (xres + hfront) / 8 + 1;
1015	_par->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
1016
1017	_par->VertRes = yres;
1018	_par->VertTotal = yres + vfront + vsync + vback - 2;
1019	_par->VertDispEnd = yres - 1;
1020	_par->VertBlankStart = yres;
1021	_par->VertBlankEnd = _par->VertTotal;
1022	_par->VertSyncStart = yres + vfront - 1;
1023	_par->VertSyncEnd = yres + vfront + vsync - 1;
1024
1025	if (_par->VertRes >= 1024) {
1026		_par->VertTotal /= 2;
1027		_par->VertSyncStart /= 2;
1028		_par->VertSyncEnd /= 2;
1029		_par->VertDispEnd /= 2;
1030	}
1031	if (_par->multiplexing) {
1032		_par->HorizTotal /= 2;
1033		_par->HorizSyncStart /= 2;
1034		_par->HorizSyncEnd /= 2;
1035		_par->HorizDispEnd /= 2;
1036	}
1037	if (_par->VertRes >= 1280) {
1038		printk (KERN_WARNING "clgen: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
1039		DPRINTK ("EXIT - EINVAL error\n");
1040		return -EINVAL;
1041	}
1042	DPRINTK ("EXIT\n");
1043	return 0;
1044}
1045
1046
1047static int clgen_encode_var (struct fb_var_screeninfo *var, const void *par,
1048			     struct fb_info_gen *info)
1049{
1050	DPRINTK ("ENTER\n");
1051
1052	*var = ((struct clgenfb_par *) par)->var;
1053
1054	DPRINTK ("EXIT\n");
1055	return 0;
1056}
1057
1058/* get current video mode */
1059static void clgen_get_par (void *par, struct fb_info_gen *info)
1060{
1061	struct clgenfb_par *_par = (struct clgenfb_par *) par;
1062	struct clgenfb_info *_info = (struct clgenfb_info *) info;
1063
1064	DPRINTK ("ENTER\n");
1065
1066	*_par = _info->currentmode;
1067
1068	DPRINTK ("EXIT\n");
1069}
1070
1071static void clgen_set_mclk (const struct clgenfb_info *fb_info, int val, int div)
1072{
1073	assert (fb_info != NULL);
1074
1075	if (div == 2) {
1076		/* VCLK = MCLK/2 */
1077		unsigned char old = vga_rseq (fb_info->regs, CL_SEQR1E);
1078		vga_wseq (fb_info->regs, CL_SEQR1E, old | 0x1);
1079		vga_wseq (fb_info->regs, CL_SEQR1F, 0x40 | (val & 0x3f));
1080	} else if (div == 1) {
1081		/* VCLK = MCLK */
1082		unsigned char old = vga_rseq (fb_info->regs, CL_SEQR1E);
1083		vga_wseq (fb_info->regs, CL_SEQR1E, old & ~0x1);
1084		vga_wseq (fb_info->regs, CL_SEQR1F, 0x40 | (val & 0x3f));
1085	} else {
1086		vga_wseq (fb_info->regs, CL_SEQR1F, val & 0x3f);
1087	}
1088}
1089
1090/*************************************************************************
1091	clgen_set_par()
1092
1093	actually writes the values for a new video mode into the hardware,
1094**************************************************************************/
1095static void clgen_set_par (const void *par, struct fb_info_gen *info)
1096{
1097	unsigned char tmp;
1098	int offset = 0;
1099	struct clgenfb_par *_par = (struct clgenfb_par *) par;
1100	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1101	const struct clgen_board_info_rec *bi;
1102
1103	DPRINTK ("ENTER\n");
1104	DPRINTK ("Requested mode: %dx%dx%d\n",
1105	       _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
1106	DPRINTK ("pixclock: %d\n", _par->var.pixclock);
1107
1108	bi = &clgen_board_info[fb_info->btype];
1109
1110
1111	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
1112	vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
1113
1114	/* if debugging is enabled, all parameters get output before writing */
1115	DPRINTK ("CRT0: %ld\n", _par->HorizTotal);
1116	vga_wcrt (fb_info->regs, VGA_CRTC_H_TOTAL, _par->HorizTotal);
1117
1118	DPRINTK ("CRT1: %ld\n", _par->HorizDispEnd);
1119	vga_wcrt (fb_info->regs, VGA_CRTC_H_DISP, _par->HorizDispEnd);
1120
1121	DPRINTK ("CRT2: %ld\n", _par->HorizBlankStart);
1122	vga_wcrt (fb_info->regs, VGA_CRTC_H_BLANK_START, _par->HorizBlankStart);
1123
1124	DPRINTK ("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32);	/*  + 128: Compatible read */
1125	vga_wcrt (fb_info->regs, VGA_CRTC_H_BLANK_END, 128 + (_par->HorizBlankEnd % 32));
1126
1127	DPRINTK ("CRT4: %ld\n", _par->HorizSyncStart);
1128	vga_wcrt (fb_info->regs, VGA_CRTC_H_SYNC_START, _par->HorizSyncStart);
1129
1130	tmp = _par->HorizSyncEnd % 32;
1131	if (_par->HorizBlankEnd & 32)
1132		tmp += 128;
1133	DPRINTK ("CRT5: %d\n", tmp);
1134	vga_wcrt (fb_info->regs, VGA_CRTC_H_SYNC_END, tmp);
1135
1136	DPRINTK ("CRT6: %ld\n", _par->VertTotal & 0xff);
1137	vga_wcrt (fb_info->regs, VGA_CRTC_V_TOTAL, (_par->VertTotal & 0xff));
1138
1139	tmp = 16;		/* LineCompare bit #9 */
1140	if (_par->VertTotal & 256)
1141		tmp |= 1;
1142	if (_par->VertDispEnd & 256)
1143		tmp |= 2;
1144	if (_par->VertSyncStart & 256)
1145		tmp |= 4;
1146	if (_par->VertBlankStart & 256)
1147		tmp |= 8;
1148	if (_par->VertTotal & 512)
1149		tmp |= 32;
1150	if (_par->VertDispEnd & 512)
1151		tmp |= 64;
1152	if (_par->VertSyncStart & 512)
1153		tmp |= 128;
1154	DPRINTK ("CRT7: %d\n", tmp);
1155	vga_wcrt (fb_info->regs, VGA_CRTC_OVERFLOW, tmp);
1156
1157	tmp = 0x40;		/* LineCompare bit #8 */
1158	if (_par->VertBlankStart & 512)
1159		tmp |= 0x20;
1160	if (_par->var.vmode & FB_VMODE_DOUBLE)
1161		tmp |= 0x80;
1162	DPRINTK ("CRT9: %d\n", tmp);
1163	vga_wcrt (fb_info->regs, VGA_CRTC_MAX_SCAN, tmp);
1164
1165	DPRINTK ("CRT10: %ld\n", _par->VertSyncStart & 0xff);
1166	vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_START, (_par->VertSyncStart & 0xff));
1167
1168	DPRINTK ("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16);
1169	vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, (_par->VertSyncEnd % 16 + 64 + 32));
1170
1171	DPRINTK ("CRT12: %ld\n", _par->VertDispEnd & 0xff);
1172	vga_wcrt (fb_info->regs, VGA_CRTC_V_DISP_END, (_par->VertDispEnd & 0xff));
1173
1174	DPRINTK ("CRT15: %ld\n", _par->VertBlankStart & 0xff);
1175	vga_wcrt (fb_info->regs, VGA_CRTC_V_BLANK_START, (_par->VertBlankStart & 0xff));
1176
1177	DPRINTK ("CRT16: %ld\n", _par->VertBlankEnd & 0xff);
1178	vga_wcrt (fb_info->regs, VGA_CRTC_V_BLANK_END, (_par->VertBlankEnd & 0xff));
1179
1180	DPRINTK ("CRT18: 0xff\n");
1181	vga_wcrt (fb_info->regs, VGA_CRTC_LINE_COMPARE, 0xff);
1182
1183	tmp = 0;
1184	if (_par->var.vmode & FB_VMODE_INTERLACED)
1185		tmp |= 1;
1186	if (_par->HorizBlankEnd & 64)
1187		tmp |= 16;
1188	if (_par->HorizBlankEnd & 128)
1189		tmp |= 32;
1190	if (_par->VertBlankEnd & 256)
1191		tmp |= 64;
1192	if (_par->VertBlankEnd & 512)
1193		tmp |= 128;
1194
1195	DPRINTK ("CRT1a: %d\n", tmp);
1196	vga_wcrt (fb_info->regs, CL_CRT1A, tmp);
1197
1198	/* set VCLK0 */
1199	/* hardware RefClock: 14.31818 MHz */
1200	/* formula: VClk = (OSC * N) / (D * (1+P)) */
1201	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1202
1203	vga_wseq (fb_info->regs, CL_SEQRB, _par->nom);
1204	tmp = _par->den << 1;
1205	if (_par->div != 0)
1206		tmp |= 1;
1207
1208	if ((fb_info->btype == BT_SD64) ||
1209	    (fb_info->btype == BT_ALPINE) ||
1210	    (fb_info->btype == BT_GD5480))
1211		tmp |= 0x80;	/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
1212
1213	DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
1214	vga_wseq (fb_info->regs, CL_SEQR1B, tmp);
1215
1216	if (_par->VertRes >= 1024)
1217		/* 1280x1024 */
1218		vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc7);
1219	else
1220		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1221		 * address wrap, no compat. */
1222		vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3);
1223
1224/* HAEH?        vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20);  * previously: 0x00  unlock VGA_CRTC_H_TOTAL..CRT7 */
1225
1226	/* don't know if it would hurt to also program this if no interlaced */
1227	/* mode is used, but I feel better this way.. :-) */
1228	if (_par->var.vmode & FB_VMODE_INTERLACED)
1229		vga_wcrt (fb_info->regs, VGA_CRTC_REGS, _par->HorizTotal / 2);
1230	else
1231		vga_wcrt (fb_info->regs, VGA_CRTC_REGS, 0x00);	/* interlace control */
1232
1233	vga_wseq (fb_info->regs, VGA_SEQ_CHARACTER_MAP, 0);
1234
1235	/* adjust horizontal/vertical sync type (low/high) */
1236	tmp = 0x03;		/* enable display memory & CRTC I/O address for color mode */
1237	if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT)
1238		tmp |= 0x40;
1239	if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT)
1240		tmp |= 0x80;
1241	WGen (fb_info, VGA_MIS_W, tmp);
1242
1243	vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0);	/* Screen A Preset Row-Scan register */
1244	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0);	/* text cursor on and start line */
1245	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 31);	/* text cursor end line */
1246
1247	/******************************************************
1248	 *
1249	 * 1 bpp
1250	 *
1251	 */
1252
1253	/* programming for different color depths */
1254	if (_par->var.bits_per_pixel == 1) {
1255		DPRINTK ("clgen: preparing for 1 bit deep display\n");
1256		vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0);	/* mode register */
1257
1258		/* SR07 */
1259		switch (fb_info->btype) {
1260		case BT_SD64:
1261		case BT_PICCOLO:
1262		case BT_PICASSO:
1263		case BT_SPECTRUM:
1264		case BT_PICASSO4:
1265		case BT_ALPINE:
1266		case BT_GD5480:
1267			DPRINTK (" (for GD54xx)\n");
1268			vga_wseq (fb_info->regs, CL_SEQR7,
1269				  _par->multiplexing ?
1270				  	bi->sr07_1bpp_mux : bi->sr07_1bpp);
1271			break;
1272
1273		case BT_LAGUNA:
1274			DPRINTK (" (for GD546x)\n");
1275			vga_wseq (fb_info->regs, CL_SEQR7,
1276				vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1277			break;
1278
1279		default:
1280			printk (KERN_WARNING "clgen: unknown Board\n");
1281			break;
1282		}
1283
1284		/* Extended Sequencer Mode */
1285		switch (fb_info->btype) {
1286		case BT_SD64:
1287			/* setting the SEQRF on SD64 is not necessary (only during init) */
1288			DPRINTK ("(for SD64)\n");
1289			vga_wseq (fb_info->regs, CL_SEQR1F, 0x1a);		/*  MCLK select */
1290			break;
1291
1292		case BT_PICCOLO:
1293			DPRINTK ("(for Piccolo)\n");
1294/* ### ueberall 0x22? */
1295			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ##vorher 1c MCLK select */
1296			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1297			break;
1298
1299		case BT_PICASSO:
1300			DPRINTK ("(for Picasso)\n");
1301			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ##vorher 22 MCLK select */
1302			vga_wseq (fb_info->regs, CL_SEQRF, 0xd0);	/* ## vorher d0 avoid FIFO underruns..? */
1303			break;
1304
1305		case BT_SPECTRUM:
1306			DPRINTK ("(for Spectrum)\n");
1307/* ### ueberall 0x22? */
1308			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ##vorher 1c MCLK select */
1309			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* evtl d0? avoid FIFO underruns..? */
1310			break;
1311
1312		case BT_PICASSO4:
1313		case BT_ALPINE:
1314		case BT_GD5480:
1315		case BT_LAGUNA:
1316			DPRINTK (" (for GD54xx)\n");
1317			/* do nothing */
1318			break;
1319
1320		default:
1321			printk (KERN_WARNING "clgen: unknown Board\n");
1322			break;
1323		}
1324
1325		WGen (fb_info, VGA_PEL_MSK, 0x01);	/* pixel mask: pass-through for first plane */
1326		if (_par->multiplexing)
1327			WHDR (fb_info, 0x4a);	/* hidden dac reg: 1280x1024 */
1328		else
1329			WHDR (fb_info, 0);	/* hidden dac: nothing */
1330		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x06);	/* memory mode: odd/even, ext. memory */
1331		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0x01);	/* plane mask: only write to first plane */
1332		offset = _par->var.xres_virtual / 16;
1333	}
1334
1335	/******************************************************
1336	 *
1337	 * 8 bpp
1338	 *
1339	 */
1340
1341	else if (_par->var.bits_per_pixel == 8) {
1342		DPRINTK ("clgen: preparing for 8 bit deep display\n");
1343		switch (fb_info->btype) {
1344		case BT_SD64:
1345		case BT_PICCOLO:
1346		case BT_PICASSO:
1347		case BT_SPECTRUM:
1348		case BT_PICASSO4:
1349		case BT_ALPINE:
1350		case BT_GD5480:
1351			DPRINTK (" (for GD54xx)\n");
1352			vga_wseq (fb_info->regs, CL_SEQR7,
1353				  _par->multiplexing ?
1354				  	bi->sr07_8bpp_mux : bi->sr07_8bpp);
1355			break;
1356
1357		case BT_LAGUNA:
1358			DPRINTK (" (for GD546x)\n");
1359			vga_wseq (fb_info->regs, CL_SEQR7,
1360				vga_rseq (fb_info->regs, CL_SEQR7) | 0x01);
1361			break;
1362
1363		default:
1364			printk (KERN_WARNING "clgen: unknown Board\n");
1365			break;
1366		}
1367
1368		switch (fb_info->btype) {
1369		case BT_SD64:
1370			vga_wseq (fb_info->regs, CL_SEQR1F, 0x1d);		/* MCLK select */
1371			break;
1372
1373		case BT_PICCOLO:
1374			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
1375			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1376			break;
1377
1378		case BT_PICASSO:
1379			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
1380			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1381			break;
1382
1383		case BT_SPECTRUM:
1384			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
1385			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1386			break;
1387
1388		case BT_PICASSO4:
1389#ifdef CONFIG_ZORRO
1390			vga_wseq (fb_info->regs, CL_SEQRF, 0xb8);	/* ### INCOMPLETE!! */
1391#endif
1392/*          vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1393			break;
1394
1395		case BT_ALPINE:
1396			DPRINTK (" (for GD543x)\n");
1397			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1398			/* We already set SRF and SR1F */
1399			break;
1400
1401		case BT_GD5480:
1402		case BT_LAGUNA:
1403			DPRINTK (" (for GD54xx)\n");
1404			/* do nothing */
1405			break;
1406
1407		default:
1408			printk (KERN_WARNING "clgen: unknown Board\n");
1409			break;
1410		}
1411
1412		vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64);	/* mode register: 256 color mode */
1413		WGen (fb_info, VGA_PEL_MSK, 0xff);	/* pixel mask: pass-through all planes */
1414		if (_par->multiplexing)
1415			WHDR (fb_info, 0x4a);	/* hidden dac reg: 1280x1024 */
1416		else
1417			WHDR (fb_info, 0);	/* hidden dac: nothing */
1418		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
1419		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
1420		offset = _par->var.xres_virtual / 8;
1421	}
1422
1423	/******************************************************
1424	 *
1425	 * 16 bpp
1426	 *
1427	 */
1428
1429	else if (_par->var.bits_per_pixel == 16) {
1430		DPRINTK ("clgen: preparing for 16 bit deep display\n");
1431		switch (fb_info->btype) {
1432		case BT_SD64:
1433			vga_wseq (fb_info->regs, CL_SEQR7, 0xf7);	/* Extended Sequencer Mode: 256c col. mode */
1434			vga_wseq (fb_info->regs, CL_SEQR1F, 0x1e);		/* MCLK select */
1435			break;
1436
1437		case BT_PICCOLO:
1438			vga_wseq (fb_info->regs, CL_SEQR7, 0x87);
1439			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1440			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* MCLK select */
1441			break;
1442
1443		case BT_PICASSO:
1444			vga_wseq (fb_info->regs, CL_SEQR7, 0x27);
1445			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1446			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* MCLK select */
1447			break;
1448
1449		case BT_SPECTRUM:
1450			vga_wseq (fb_info->regs, CL_SEQR7, 0x87);
1451			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1452			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* MCLK select */
1453			break;
1454
1455		case BT_PICASSO4:
1456			vga_wseq (fb_info->regs, CL_SEQR7, 0x27);
1457/*          vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c);  */
1458			break;
1459
1460		case BT_ALPINE:
1461			DPRINTK (" (for GD543x)\n");
1462			if (_par->HorizRes >= 1024)
1463				vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
1464			else
1465				vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
1466			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1467			break;
1468
1469		case BT_GD5480:
1470			DPRINTK (" (for GD5480)\n");
1471			vga_wseq (fb_info->regs, CL_SEQR7, 0x17);
1472			/* We already set SRF and SR1F */
1473			break;
1474
1475		case BT_LAGUNA:
1476			DPRINTK (" (for GD546x)\n");
1477			vga_wseq (fb_info->regs, CL_SEQR7,
1478				vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1479			break;
1480
1481		default:
1482			printk (KERN_WARNING "CLGEN: unknown Board\n");
1483			break;
1484		}
1485
1486		vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64);	/* mode register: 256 color mode */
1487		WGen (fb_info, VGA_PEL_MSK, 0xff);	/* pixel mask: pass-through all planes */
1488#ifdef CONFIG_PCI
1489		WHDR (fb_info, 0xc0);	/* Copy Xbh */
1490#elif defined(CONFIG_ZORRO)
1491		WHDR (fb_info, 0xa0);	/* hidden dac reg: nothing special */
1492#endif
1493		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
1494		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
1495		offset = _par->var.xres_virtual / 4;
1496	}
1497
1498	/******************************************************
1499	 *
1500	 * 32 bpp
1501	 *
1502	 */
1503
1504	else if (_par->var.bits_per_pixel == 32) {
1505		DPRINTK ("clgen: preparing for 24/32 bit deep display\n");
1506		switch (fb_info->btype) {
1507		case BT_SD64:
1508			vga_wseq (fb_info->regs, CL_SEQR7, 0xf9);	/* Extended Sequencer Mode: 256c col. mode */
1509			vga_wseq (fb_info->regs, CL_SEQR1F, 0x1e);		/* MCLK select */
1510			break;
1511
1512		case BT_PICCOLO:
1513			vga_wseq (fb_info->regs, CL_SEQR7, 0x85);
1514			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1515			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* MCLK select */
1516			break;
1517
1518		case BT_PICASSO:
1519			vga_wseq (fb_info->regs, CL_SEQR7, 0x25);
1520			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1521			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* MCLK select */
1522			break;
1523
1524		case BT_SPECTRUM:
1525			vga_wseq (fb_info->regs, CL_SEQR7, 0x85);
1526			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
1527			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* MCLK select */
1528			break;
1529
1530		case BT_PICASSO4:
1531			vga_wseq (fb_info->regs, CL_SEQR7, 0x25);
1532/*          vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c);  */
1533			break;
1534
1535		case BT_ALPINE:
1536			DPRINTK (" (for GD543x)\n");
1537			vga_wseq (fb_info->regs, CL_SEQR7, 0xa9);
1538			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1539			break;
1540
1541		case BT_GD5480:
1542			DPRINTK (" (for GD5480)\n");
1543			vga_wseq (fb_info->regs, CL_SEQR7, 0x19);
1544			/* We already set SRF and SR1F */
1545			break;
1546
1547		case BT_LAGUNA:
1548			DPRINTK (" (for GD546x)\n");
1549			vga_wseq (fb_info->regs, CL_SEQR7,
1550				vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1551			break;
1552
1553		default:
1554			printk (KERN_WARNING "clgen: unknown Board\n");
1555			break;
1556		}
1557
1558		vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64);	/* mode register: 256 color mode */
1559		WGen (fb_info, VGA_PEL_MSK, 0xff);	/* pixel mask: pass-through all planes */
1560		WHDR (fb_info, 0xc5);	/* hidden dac reg: 8-8-8 mode (24 or 32) */
1561		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
1562		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
1563		offset = _par->var.xres_virtual / 4;
1564	}
1565
1566	/******************************************************
1567	 *
1568	 * unknown/unsupported bpp
1569	 *
1570	 */
1571
1572	else {
1573		printk (KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
1574			_par->var.bits_per_pixel);
1575	}
1576
1577	vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
1578	tmp = 0x22;
1579	if (offset & 0x100)
1580		tmp |= 0x10;	/* offset overflow bit */
1581
1582	vga_wcrt (fb_info->regs, CL_CRT1B, tmp);	/* screen start addr #16-18, fastpagemode cycles */
1583
1584	if (fb_info->btype == BT_SD64 ||
1585	    fb_info->btype == BT_PICASSO4 ||
1586	    fb_info->btype == BT_ALPINE ||
1587	    fb_info->btype == BT_GD5480)
1588		vga_wcrt (fb_info->regs, CL_CRT1D, 0x00);	/* screen start address bit 19 */
1589
1590	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_HI, 0);	/* text cursor location high */
1591	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_LO, 0);	/* text cursor location low */
1592	vga_wcrt (fb_info->regs, VGA_CRTC_UNDERLINE, 0);	/* underline row scanline = at very bottom */
1593
1594	vga_wattr (fb_info->regs, VGA_ATC_MODE, 1);	/* controller mode */
1595	vga_wattr (fb_info->regs, VGA_ATC_OVERSCAN, 0);		/* overscan (border) color */
1596	vga_wattr (fb_info->regs, VGA_ATC_PLANE_ENABLE, 15);	/* color plane enable */
1597	vga_wattr (fb_info->regs, CL_AR33, 0);	/* pixel panning */
1598	vga_wattr (fb_info->regs, VGA_ATC_COLOR_PAGE, 0);	/* color select */
1599
1600	/* [ EGS: SetOffset(); ] */
1601	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1602	AttrOn (fb_info);
1603
1604	vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, 0);	/* set/reset register */
1605	vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, 0);		/* set/reset enable */
1606	vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_VALUE, 0);	/* color compare */
1607	vga_wgfx (fb_info->regs, VGA_GFX_DATA_ROTATE, 0);	/* data rotate */
1608	vga_wgfx (fb_info->regs, VGA_GFX_PLANE_READ, 0);	/* read map select */
1609	vga_wgfx (fb_info->regs, VGA_GFX_MISC, 1);	/* miscellaneous register */
1610	vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_MASK, 15);	/* color don't care */
1611	vga_wgfx (fb_info->regs, VGA_GFX_BIT_MASK, 255);	/* bit mask */
1612
1613	vga_wseq (fb_info->regs, CL_SEQR12, 0x0);	/* graphics cursor attributes: nothing special */
1614
1615	/* finally, turn on everything - turn off "FullBandwidth" bit */
1616	/* also, set "DotClock%2" bit where requested */
1617	tmp = 0x01;
1618
1619/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1620    if (var->vmode & FB_VMODE_CLOCK_HALVE)
1621	tmp |= 0x08;
1622*/
1623
1624	vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, tmp);
1625	DPRINTK ("CL_SEQR1: %d\n", tmp);
1626
1627	fb_info->currentmode = *_par;
1628
1629	DPRINTK ("virtual offset: (%d,%d)\n", _par->var.xoffset, _par->var.yoffset);
1630	/* pan to requested offset */
1631	clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen *) fb_info);
1632
1633#ifdef CLGEN_DEBUG
1634	clgen_dump ();
1635#endif
1636
1637	DPRINTK ("EXIT\n");
1638	return;
1639}
1640
1641
1642static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green,
1643			    unsigned *blue, unsigned *transp,
1644			    struct fb_info *info)
1645{
1646    struct clgenfb_info *fb_info = (struct clgenfb_info *)info;
1647
1648    if (regno > 255)
1649	return 1;
1650    *red = fb_info->palette[regno].red;
1651    *green = fb_info->palette[regno].green;
1652    *blue = fb_info->palette[regno].blue;
1653    *transp = 0;
1654    return 0;
1655}
1656
1657
1658static int clgen_setcolreg (unsigned regno, unsigned red, unsigned green,
1659			    unsigned blue, unsigned transp,
1660			    struct fb_info *info)
1661{
1662	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1663
1664	if (regno > 255)
1665		return -EINVAL;
1666
1667#ifdef FBCON_HAS_CFB8
1668	switch (fb_info->currentmode.var.bits_per_pixel) {
1669	case 8:
1670		/* "transparent" stuff is completely ignored. */
1671		WClut (fb_info, regno, red >> 10, green >> 10, blue >> 10);
1672		break;
1673	default:
1674		/* do nothing */
1675		break;
1676	}
1677#endif	/* FBCON_HAS_CFB8 */
1678
1679	fb_info->palette[regno].red = red;
1680	fb_info->palette[regno].green = green;
1681	fb_info->palette[regno].blue = blue;
1682
1683	if (regno >= 16)
1684		return 0;
1685
1686	switch (fb_info->currentmode.var.bits_per_pixel) {
1687
1688#ifdef FBCON_HAS_CFB16
1689	case 16:
1690		assert (regno < 16);
1691		if(isPReP) {
1692			fb_info->fbcon_cmap.cfb16[regno] =
1693			    ((red & 0xf800) >> 9) |
1694			    ((green & 0xf800) >> 14) |
1695			    ((green & 0xf800) << 2) |
1696			    ((blue & 0xf800) >> 3);
1697		} else {
1698			fb_info->fbcon_cmap.cfb16[regno] =
1699			    ((red & 0xf800) >> 1) |
1700			    ((green & 0xf800) >> 6) |
1701			    ((blue & 0xf800) >> 11);
1702		}
1703#endif /* FBCON_HAS_CFB16 */
1704
1705#ifdef FBCON_HAS_CFB24
1706	case 24:
1707		assert (regno < 16);
1708		fb_info->fbcon_cmap.cfb24[regno] =
1709			(red   << fb_info->currentmode.var.red.offset)   |
1710			(green << fb_info->currentmode.var.green.offset) |
1711			(blue  << fb_info->currentmode.var.blue.offset);
1712		break;
1713#endif /* FBCON_HAS_CFB24 */
1714
1715#ifdef FBCON_HAS_CFB32
1716	case 32:
1717		assert (regno < 16);
1718		if(isPReP) {
1719			fb_info->fbcon_cmap.cfb32[regno] =
1720			    ((red & 0xff00)) |
1721			    ((green & 0xff00) << 8) |
1722			    ((blue & 0xff00) << 16);
1723		} else {
1724			fb_info->fbcon_cmap.cfb32[regno] =
1725			    ((red & 0xff00) << 8) |
1726			    ((green & 0xff00)) |
1727			    ((blue & 0xff00) >> 8);
1728		}
1729		break;
1730#endif /* FBCON_HAS_CFB32 */
1731	default:
1732		/* do nothing */
1733		break;
1734	}
1735
1736	return 0;
1737}
1738
1739/*************************************************************************
1740	clgen_pan_display()
1741
1742	performs display panning - provided hardware permits this
1743**************************************************************************/
1744static int clgen_pan_display (const struct fb_var_screeninfo *var,
1745			      struct fb_info_gen *info)
1746{
1747	int xoffset = 0;
1748	int yoffset = 0;
1749	unsigned long base;
1750	unsigned char tmp = 0, tmp2 = 0, xpix;
1751	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1752
1753	DPRINTK ("ENTER\n");
1754
1755	/* no range checks for xoffset and yoffset,   */
1756	/* as fbgen_pan_display has already done this */
1757
1758	fb_info->currentmode.var.xoffset = var->xoffset;
1759	fb_info->currentmode.var.yoffset = var->yoffset;
1760
1761	xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8;
1762	yoffset = var->yoffset;
1763
1764	base = yoffset * fb_info->currentmode.line_length + xoffset;
1765
1766	if (fb_info->currentmode.var.bits_per_pixel == 1) {
1767		/* base is already correct */
1768		xpix = (unsigned char) (var->xoffset % 8);
1769	} else {
1770		base /= 4;
1771		xpix = (unsigned char) ((xoffset % 4) * 2);
1772	}
1773
1774	/* lower 8 + 8 bits of screen start address */
1775	vga_wcrt (fb_info->regs, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
1776	vga_wcrt (fb_info->regs, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
1777
1778	/* construct bits 16, 17 and 18 of screen start address */
1779	if (base & 0x10000)
1780		tmp |= 0x01;
1781	if (base & 0x20000)
1782		tmp |= 0x04;
1783	if (base & 0x40000)
1784		tmp |= 0x08;
1785
1786	tmp2 = (vga_rcrt (fb_info->regs, CL_CRT1B) & 0xf2) | tmp;	/* 0xf2 is %11110010, exclude tmp bits */
1787	vga_wcrt (fb_info->regs, CL_CRT1B, tmp2);
1788
1789	/* construct bit 19 of screen start address */
1790	if (clgen_board_info[fb_info->btype].scrn_start_bit19) {
1791		tmp2 = 0;
1792		if (base & 0x80000)
1793			tmp2 = 0x80;
1794		vga_wcrt (fb_info->regs, CL_CRT1D, tmp2);
1795	}
1796
1797	/* write pixel panning value to AR33; this does not quite work in 8bpp */
1798	/* ### Piccolo..? Will this work? */
1799	if (fb_info->currentmode.var.bits_per_pixel == 1)
1800		vga_wattr (fb_info->regs, CL_AR33, xpix);
1801
1802
1803	DPRINTK ("EXIT\n");
1804	return (0);
1805}
1806
1807
1808static int clgen_blank (int blank_mode, struct fb_info_gen *info)
1809{
1810	/*
1811	 *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1812	 *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
1813	 *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
1814	 *  to e.g. a video mode which doesn't support it. Implements VESA suspend
1815	 *  and powerdown modes on hardware that supports disabling hsync/vsync:
1816	 *    blank_mode == 2: suspend vsync
1817	 *    blank_mode == 3: suspend hsync
1818	 *    blank_mode == 4: powerdown
1819	 */
1820	unsigned char val;
1821	static int current_mode = 0;
1822	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1823
1824	DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
1825
1826	if (current_mode == blank_mode) {
1827		DPRINTK ("EXIT, returning 0\n");
1828		return 0;
1829	}
1830
1831	/* Undo current */
1832	switch (current_mode) {
1833	case 0:		/* Screen is normal */
1834		break;
1835	case 1:		/* Screen is blanked */
1836		val = vga_rseq (fb_info->regs, VGA_SEQ_CLOCK_MODE);
1837		vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, val & 0xdf);	/* clear "FullBandwidth" bit */
1838		break;
1839	case 2:		/* vsync suspended */
1840	case 3:		/* hsync suspended */
1841	case 4:		/* sceen is powered down */
1842		vga_wgfx (fb_info->regs, CL_GRE, 0x00);
1843		break;
1844	default:
1845		DPRINTK ("EXIT, returning 1\n");
1846		return 1;
1847	}
1848
1849	/* set new */
1850	switch (blank_mode) {
1851	case 0:		/* Unblank screen */
1852		break;
1853	case 1:		/* Blank screen */
1854		val = vga_rseq (fb_info->regs, VGA_SEQ_CLOCK_MODE);
1855		vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, val | 0x20);	/* set "FullBandwidth" bit */
1856		break;
1857	case 2:		/* suspend vsync */
1858		vga_wgfx (fb_info->regs, CL_GRE, 0x04);
1859		break;
1860	case 3:		/* suspend hsync */
1861		vga_wgfx (fb_info->regs, CL_GRE, 0x02);
1862		break;
1863	case 4:		/* powerdown */
1864		vga_wgfx (fb_info->regs, CL_GRE, 0x06);
1865		break;
1866	default:
1867		DPRINTK ("EXIT, returning 1\n");
1868		return 1;
1869	}
1870
1871	current_mode = blank_mode;
1872	DPRINTK ("EXIT, returning 0\n");
1873	return 0;
1874}
1875/**** END   Hardware specific Routines **************************************/
1876/****************************************************************************/
1877/**** BEGIN Internal Routines ***********************************************/
1878
1879static void __init init_vgachip (struct clgenfb_info *fb_info)
1880{
1881	const struct clgen_board_info_rec *bi;
1882
1883	DPRINTK ("ENTER\n");
1884
1885	assert (fb_info != NULL);
1886
1887	bi = &clgen_board_info[fb_info->btype];
1888
1889	/* reset board globally */
1890	switch (fb_info->btype) {
1891	case BT_PICCOLO:
1892		WSFR (fb_info, 0x01);
1893		udelay (500);
1894		WSFR (fb_info, 0x51);
1895		udelay (500);
1896		break;
1897	case BT_PICASSO:
1898		WSFR2 (fb_info, 0xff);
1899		udelay (500);
1900		break;
1901	case BT_SD64:
1902	case BT_SPECTRUM:
1903		WSFR (fb_info, 0x1f);
1904		udelay (500);
1905		WSFR (fb_info, 0x4f);
1906		udelay (500);
1907		break;
1908	case BT_PICASSO4:
1909		vga_wcrt (fb_info->regs, CL_CRT51, 0x00);	/* disable flickerfixer */
1910		mdelay (100);
1911		vga_wgfx (fb_info->regs, CL_GR2F, 0x00);	/* from Klaus' NetBSD driver: */
1912		vga_wgfx (fb_info->regs, CL_GR33, 0x00);	/* put blitter into 542x compat */
1913		vga_wgfx (fb_info->regs, CL_GR31, 0x00);	/* mode */
1914		break;
1915
1916	case BT_GD5480:
1917		vga_wgfx (fb_info->regs, CL_GR2F, 0x00);	/* from Klaus' NetBSD driver: */
1918		break;
1919
1920	case BT_ALPINE:
1921		/* Nothing to do to reset the board. */
1922		break;
1923
1924	default:
1925		printk (KERN_ERR "clgen: Warning: Unknown board type\n");
1926		break;
1927	}
1928
1929	assert (fb_info->size > 0); /* make sure RAM size set by this point */
1930
1931	/* assume it's a "large memory" board (2/4 MB) */
1932	fb_info->smallboard = FALSE;
1933
1934	/* the P4 is not fully initialized here; I rely on it having been */
1935	/* inited under AmigaOS already, which seems to work just fine    */
1936	/* (Klaus advised to do it this way)                              */
1937
1938	if (fb_info->btype != BT_PICASSO4) {
1939		WGen (fb_info, CL_VSSM, 0x10);	/* EGS: 0x16 */
1940		WGen (fb_info, CL_POS102, 0x01);
1941		WGen (fb_info, CL_VSSM, 0x08);	/* EGS: 0x0e */
1942
1943		if (fb_info->btype != BT_SD64)
1944			WGen (fb_info, CL_VSSM2, 0x01);
1945
1946		vga_wseq (fb_info->regs, CL_SEQR0, 0x03);	/* reset sequencer logic */
1947
1948		vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, 0x21);	/* FullBandwidth (video off) and 8/9 dot clock */
1949		WGen (fb_info, VGA_MIS_W, 0xc1);	/* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
1950
1951/*      vga_wgfx (fb_info->regs, CL_GRA, 0xce);    "magic cookie" - doesn't make any sense to me.. */
1952		vga_wseq (fb_info->regs, CL_SEQR6, 0x12);	/* unlock all extension registers */
1953
1954		vga_wgfx (fb_info->regs, CL_GR31, 0x04);	/* reset blitter */
1955
1956		switch (fb_info->btype) {
1957		case BT_GD5480:
1958			vga_wseq (fb_info->regs, CL_SEQRF, 0x98);
1959			break;
1960		case BT_ALPINE:
1961			break;
1962		case BT_SD64:
1963			vga_wseq (fb_info->regs, CL_SEQRF, 0xb8);
1964			break;
1965		default:
1966			vga_wseq (fb_info->regs, CL_SEQR16, 0x0f);
1967			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);
1968			break;
1969		}
1970	}
1971	vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: nothing */
1972	vga_wseq (fb_info->regs, VGA_SEQ_CHARACTER_MAP, 0x00);	/* character map select: doesn't even matter in gx mode */
1973	vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0e);	/* memory mode: chain-4, no odd/even, ext. memory */
1974
1975	/* controller-internal base address of video memory */
1976	if (bi->init_sr07)
1977		vga_wseq (fb_info->regs, CL_SEQR7, bi->sr07);
1978
1979	/*  vga_wseq (fb_info->regs, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
1980
1981	vga_wseq (fb_info->regs, CL_SEQR10, 0x00);		/* graphics cursor X position (incomplete; position gives rem. 3 bits */
1982	vga_wseq (fb_info->regs, CL_SEQR11, 0x00);		/* graphics cursor Y position (..."... ) */
1983	vga_wseq (fb_info->regs, CL_SEQR12, 0x00);		/* graphics cursor attributes */
1984	vga_wseq (fb_info->regs, CL_SEQR13, 0x00);		/* graphics cursor pattern address */
1985
1986	/* writing these on a P4 might give problems..  */
1987	if (fb_info->btype != BT_PICASSO4) {
1988		vga_wseq (fb_info->regs, CL_SEQR17, 0x00);		/* configuration readback and ext. color */
1989		vga_wseq (fb_info->regs, CL_SEQR18, 0x02);		/* signature generator */
1990	}
1991
1992	/* MCLK select etc. */
1993	if (bi->init_sr1f)
1994		vga_wseq (fb_info->regs, CL_SEQR1F, bi->sr1f);
1995
1996	vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0x00);	/* Screen A preset row scan: none */
1997	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0x20);	/* Text cursor start: disable text cursor */
1998	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 0x00);	/* Text cursor end: - */
1999	vga_wcrt (fb_info->regs, VGA_CRTC_START_HI, 0x00);	/* Screen start address high: 0 */
2000	vga_wcrt (fb_info->regs, VGA_CRTC_START_LO, 0x00);	/* Screen start address low: 0 */
2001	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_HI, 0x00);	/* text cursor location high: 0 */
2002	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_LO, 0x00);	/* text cursor location low: 0 */
2003
2004	vga_wcrt (fb_info->regs, VGA_CRTC_UNDERLINE, 0x00);	/* Underline Row scanline: - */
2005	vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3);	/* mode control: timing enable, byte mode, no compat modes */
2006	vga_wcrt (fb_info->regs, VGA_CRTC_LINE_COMPARE, 0x00);	/* Line Compare: not needed */
2007	/* ### add 0x40 for text modes with > 30 MHz pixclock */
2008	vga_wcrt (fb_info->regs, CL_CRT1B, 0x02);	/* ext. display controls: ext.adr. wrap */
2009
2010	vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, 0x00);	/* Set/Reset registes: - */
2011	vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, 0x00);	/* Set/Reset enable: - */
2012	vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_VALUE, 0x00);	/* Color Compare: - */
2013	vga_wgfx (fb_info->regs, VGA_GFX_DATA_ROTATE, 0x00);	/* Data Rotate: - */
2014	vga_wgfx (fb_info->regs, VGA_GFX_PLANE_READ, 0x00);	/* Read Map Select: - */
2015	vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0x00);	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
2016	vga_wgfx (fb_info->regs, VGA_GFX_MISC, 0x01);	/* Miscellaneous: memory map base address, graphics mode */
2017	vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_MASK, 0x0f);	/* Color Don't care: involve all planes */
2018	vga_wgfx (fb_info->regs, VGA_GFX_BIT_MASK, 0xff);	/* Bit Mask: no mask at all */
2019	if (fb_info->btype == BT_ALPINE)
2020		vga_wgfx (fb_info->regs, CL_GRB, 0x20);	/* (5434 can't have bit 3 set for bitblt) */
2021	else
2022		vga_wgfx (fb_info->regs, CL_GRB, 0x28);	/* Graphics controller mode extensions: finer granularity, 8byte data latches */
2023
2024	vga_wgfx (fb_info->regs, CL_GRC, 0xff);	/* Color Key compare: - */
2025	vga_wgfx (fb_info->regs, CL_GRD, 0x00);	/* Color Key compare mask: - */
2026	vga_wgfx (fb_info->regs, CL_GRE, 0x00);	/* Miscellaneous control: - */
2027	/*  vga_wgfx (fb_info->regs, CL_GR10, 0x00); *//* Background color byte 1: - */
2028/*  vga_wgfx (fb_info->regs, CL_GR11, 0x00); */
2029
2030	vga_wattr (fb_info->regs, VGA_ATC_PALETTE0, 0x00);	/* Attribute Controller palette registers: "identity mapping" */
2031	vga_wattr (fb_info->regs, VGA_ATC_PALETTE1, 0x01);
2032	vga_wattr (fb_info->regs, VGA_ATC_PALETTE2, 0x02);
2033	vga_wattr (fb_info->regs, VGA_ATC_PALETTE3, 0x03);
2034	vga_wattr (fb_info->regs, VGA_ATC_PALETTE4, 0x04);
2035	vga_wattr (fb_info->regs, VGA_ATC_PALETTE5, 0x05);
2036	vga_wattr (fb_info->regs, VGA_ATC_PALETTE6, 0x06);
2037	vga_wattr (fb_info->regs, VGA_ATC_PALETTE7, 0x07);
2038	vga_wattr (fb_info->regs, VGA_ATC_PALETTE8, 0x08);
2039	vga_wattr (fb_info->regs, VGA_ATC_PALETTE9, 0x09);
2040	vga_wattr (fb_info->regs, VGA_ATC_PALETTEA, 0x0a);
2041	vga_wattr (fb_info->regs, VGA_ATC_PALETTEB, 0x0b);
2042	vga_wattr (fb_info->regs, VGA_ATC_PALETTEC, 0x0c);
2043	vga_wattr (fb_info->regs, VGA_ATC_PALETTED, 0x0d);
2044	vga_wattr (fb_info->regs, VGA_ATC_PALETTEE, 0x0e);
2045	vga_wattr (fb_info->regs, VGA_ATC_PALETTEF, 0x0f);
2046
2047	vga_wattr (fb_info->regs, VGA_ATC_MODE, 0x01);	/* Attribute Controller mode: graphics mode */
2048	vga_wattr (fb_info->regs, VGA_ATC_OVERSCAN, 0x00);	/* Overscan color reg.: reg. 0 */
2049	vga_wattr (fb_info->regs, VGA_ATC_PLANE_ENABLE, 0x0f);	/* Color Plane enable: Enable all 4 planes */
2050/* ###  vga_wattr (fb_info->regs, CL_AR33, 0x00); * Pixel Panning: - */
2051	vga_wattr (fb_info->regs, VGA_ATC_COLOR_PAGE, 0x00);	/* Color Select: - */
2052
2053	WGen (fb_info, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
2054
2055	if (fb_info->btype != BT_ALPINE && fb_info->btype != BT_GD5480)
2056		WGen (fb_info, VGA_MIS_W, 0xc3);	/* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
2057
2058	vga_wgfx (fb_info->regs, CL_GR31, 0x04);	/* BLT Start/status: Blitter reset */
2059	vga_wgfx (fb_info->regs, CL_GR31, 0x00);	/* - " -           : "end-of-reset" */
2060
2061	/* CLUT setup */
2062	WClut (fb_info, 0, 0x00, 0x00, 0x00);	/* background: black */
2063	WClut (fb_info, 1, 0x3f, 0x3f, 0x3f);	/* foreground: white */
2064	WClut (fb_info, 2, 0x00, 0x20, 0x00);
2065	WClut (fb_info, 3, 0x00, 0x20, 0x20);
2066	WClut (fb_info, 4, 0x20, 0x00, 0x00);
2067	WClut (fb_info, 5, 0x20, 0x00, 0x20);
2068	WClut (fb_info, 6, 0x20, 0x10, 0x00);
2069	WClut (fb_info, 7, 0x20, 0x20, 0x20);
2070	WClut (fb_info, 8, 0x10, 0x10, 0x10);
2071	WClut (fb_info, 9, 0x10, 0x10, 0x30);
2072	WClut (fb_info, 10, 0x10, 0x30, 0x10);
2073	WClut (fb_info, 11, 0x10, 0x30, 0x30);
2074	WClut (fb_info, 12, 0x30, 0x10, 0x10);
2075	WClut (fb_info, 13, 0x30, 0x10, 0x30);
2076	WClut (fb_info, 14, 0x30, 0x30, 0x10);
2077	WClut (fb_info, 15, 0x30, 0x30, 0x30);
2078
2079	/* the rest a grey ramp */
2080	{
2081		int i;
2082
2083		for (i = 16; i < 256; i++)
2084			WClut (fb_info, i, i >> 2, i >> 2, i >> 2);
2085	}
2086
2087
2088	/* misc... */
2089	WHDR (fb_info, 0);	/* Hidden DAC register: - */
2090
2091	printk (KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size);
2092	DPRINTK ("EXIT\n");
2093	return;
2094}
2095
2096static void switch_monitor (struct clgenfb_info *fb_info, int on)
2097{
2098#ifdef CONFIG_ZORRO     /* only works on Zorro boards */
2099	static int IsOn = 0;
2100
2101	DPRINTK ("ENTER\n");
2102
2103	if (fb_info->btype == BT_PICASSO4)
2104		return;		/* nothing to switch */
2105	if (fb_info->btype == BT_ALPINE)
2106		return;		/* nothing to switch */
2107	if (fb_info->btype == BT_GD5480)
2108		return;		/* nothing to switch */
2109	if (fb_info->btype == BT_PICASSO) {
2110		if ((on && !IsOn) || (!on && IsOn))
2111			WSFR (fb_info, 0xff);
2112
2113		DPRINTK ("EXIT\n");
2114		return;
2115	}
2116	if (on) {
2117		switch (fb_info->btype) {
2118		case BT_SD64:
2119			WSFR (fb_info, fb_info->SFR | 0x21);
2120			break;
2121		case BT_PICCOLO:
2122			WSFR (fb_info, fb_info->SFR | 0x28);
2123			break;
2124		case BT_SPECTRUM:
2125			WSFR (fb_info, 0x6f);
2126			break;
2127		default: /* do nothing */ break;
2128		}
2129	} else {
2130		switch (fb_info->btype) {
2131		case BT_SD64:
2132			WSFR (fb_info, fb_info->SFR & 0xde);
2133			break;
2134		case BT_PICCOLO:
2135			WSFR (fb_info, fb_info->SFR & 0xd7);
2136			break;
2137		case BT_SPECTRUM:
2138			WSFR (fb_info, 0x4f);
2139			break;
2140		default: /* do nothing */ break;
2141		}
2142	}
2143
2144	DPRINTK ("EXIT\n");
2145#endif /* CONFIG_ZORRO */
2146}
2147
2148static void clgen_set_disp (const void *par, struct display *disp,
2149			    struct fb_info_gen *info)
2150{
2151	struct clgenfb_par *_par = (struct clgenfb_par *) par;
2152	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
2153	int accel_text;
2154
2155	DPRINTK ("ENTER\n");
2156
2157	assert (_par != NULL);
2158	assert (fb_info != NULL);
2159
2160	accel_text = _par->var.accel_flags & FB_ACCELF_TEXT;
2161
2162	printk ("Cirrus Logic video mode: ");
2163	disp->screen_base = (char *) fb_info->fbmem;
2164	switch (_par->var.bits_per_pixel) {
2165#ifdef FBCON_HAS_MFB
2166	case 1:
2167		printk ("monochrome\n");
2168		if (fb_info->btype == BT_GD5480)
2169			disp->screen_base = (char *) fb_info->fbmem;
2170		disp->dispsw = &fbcon_mfb;
2171		break;
2172#endif
2173#ifdef FBCON_HAS_CFB8
2174	case 8:
2175		printk ("8 bit color depth\n");
2176		if (fb_info->btype == BT_GD5480)
2177			disp->screen_base = (char *) fb_info->fbmem;
2178		if (accel_text)
2179			disp->dispsw = &fbcon_clgen_8;
2180		else
2181			disp->dispsw = &fbcon_cfb8;
2182		break;
2183#endif
2184#ifdef FBCON_HAS_CFB16
2185	case 16:
2186		printk ("16 bit color depth\n");
2187		if (accel_text)
2188			disp->dispsw = &fbcon_clgen_16;
2189		else
2190			disp->dispsw = &fbcon_cfb16;
2191		if (fb_info->btype == BT_GD5480)
2192			disp->screen_base = (char *) fb_info->fbmem + 1 * MB_;
2193		disp->dispsw_data = fb_info->fbcon_cmap.cfb16;
2194		break;
2195#endif
2196#ifdef FBCON_HAS_CFB24
2197	case 24:
2198		printk ("24 bit color depth\n");
2199		disp->dispsw = &fbcon_cfb24;
2200		if (fb_info->btype == BT_GD5480)
2201			disp->screen_base = (char *) fb_info->fbmem + 2 * MB_;
2202		disp->dispsw_data = fb_info->fbcon_cmap.cfb24;
2203		break;
2204#endif
2205#ifdef FBCON_HAS_CFB32
2206	case 32:
2207		printk ("32 bit color depth\n");
2208		if (accel_text)
2209			disp->dispsw = &fbcon_clgen_32;
2210		else
2211			disp->dispsw = &fbcon_cfb32;
2212		if (fb_info->btype == BT_GD5480)
2213			disp->screen_base = (char *) fb_info->fbmem + 2 * MB_;
2214		disp->dispsw_data = fb_info->fbcon_cmap.cfb32;
2215		break;
2216#endif
2217
2218	default:
2219		printk ("unsupported color depth\n");
2220		disp->dispsw = &fbcon_dummy;
2221		disp->dispsw_data = NULL;
2222		break;
2223	}
2224
2225	DPRINTK ("EXIT\n");
2226}
2227
2228#ifdef FBCON_HAS_CFB8
2229static void fbcon_clgen8_bmove (struct display *p, int sy, int sx,
2230				int dy, int dx, int height, int width)
2231{
2232	struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2233
2234	DPRINTK ("ENTER\n");
2235
2236	sx *= fontwidth (p);
2237	sy *= fontheight (p);
2238	dx *= fontwidth (p);
2239	dy *= fontheight (p);
2240	width *= fontwidth (p);
2241	height *= fontheight (p);
2242
2243	clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2244		      (unsigned short) dx, (unsigned short) dy,
2245		      (unsigned short) width, (unsigned short) height,
2246		      fb_info->currentmode.line_length);
2247
2248	DPRINTK ("EXIT\n");
2249}
2250
2251static void fbcon_clgen8_clear (struct vc_data *conp, struct display *p,
2252				int sy, int sx, int height, int width)
2253{
2254	struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2255	unsigned short col;
2256
2257	DPRINTK ("ENTER\n");
2258
2259	sx *= fontwidth (p);
2260	sy *= fontheight (p);
2261	width *= fontwidth (p);
2262	height *= fontheight (p);
2263
2264	col = attr_bgcol_ec (p, conp);
2265	col &= 0xff;
2266
2267	clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2268			(unsigned short) width, (unsigned short) height,
2269			col, fb_info->currentmode.line_length);
2270
2271	DPRINTK ("EXIT\n");
2272}
2273
2274#endif
2275
2276#ifdef FBCON_HAS_CFB16
2277static void fbcon_clgen16_bmove (struct display *p, int sy, int sx,
2278				 int dy, int dx, int height, int width)
2279{
2280	struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2281
2282	DPRINTK ("ENTER\n");
2283
2284	sx *= fontwidth (p) * 2;	/* 2 bytes/pixel */
2285	sy *= fontheight (p);
2286	dx *= fontwidth (p) * 2;	/* 2 bytes/pixel */
2287	dy *= fontheight (p);
2288	width *= fontwidth (p) * 2;	/* 2 bytes/pixel */
2289	height *= fontheight (p);
2290
2291	clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2292		      (unsigned short) dx, (unsigned short) dy,
2293		      (unsigned short) width, (unsigned short) height,
2294		      fb_info->currentmode.line_length);
2295
2296	DPRINTK ("EXIT\n");
2297}
2298
2299static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
2300				 int sy, int sx, int height, int width)
2301{
2302	struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2303	unsigned short col;
2304
2305	DPRINTK ("ENTER\n");
2306
2307	sx *= fontwidth (p) * 2;	/* 2 bytes/pixel */
2308	sy *= fontheight (p);
2309	width *= fontwidth (p) * 2;	/* 2 bytes/pixel? */
2310	height *= fontheight (p);
2311
2312	col = attr_bgcol_ec (p, conp);
2313	col &= 0xff;
2314
2315	clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2316			(unsigned short) width, (unsigned short) height,
2317			col, fb_info->currentmode.line_length);
2318
2319	DPRINTK ("EXIT\n");
2320}
2321
2322#endif
2323
2324#ifdef FBCON_HAS_CFB32
2325static void fbcon_clgen32_bmove (struct display *p, int sy, int sx,
2326				 int dy, int dx, int height, int width)
2327{
2328	struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2329
2330	DPRINTK ("ENTER\n");
2331
2332	sx *= fontwidth (p) * 4;	/* 4 bytes/pixel */
2333	sy *= fontheight (p);
2334	dx *= fontwidth (p) * 4;	/* 4 bytes/pixel */
2335	dy *= fontheight (p);
2336	width *= fontwidth (p) * 4;	/* 4 bytes/pixel */
2337	height *= fontheight (p);
2338
2339	clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2340		      (unsigned short) dx, (unsigned short) dy,
2341		      (unsigned short) width, (unsigned short) height,
2342		      fb_info->currentmode.line_length);
2343
2344	DPRINTK ("EXIT\n");
2345}
2346
2347static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
2348				 int sy, int sx, int height, int width)
2349{
2350	struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2351
2352	unsigned short col;
2353
2354	DPRINTK ("ENTER\n");
2355
2356	sx *= fontwidth (p) * 4;	/* 4 bytes/pixel */
2357	sy *= fontheight (p);
2358	width *= fontwidth (p) * 4;	/* 4 bytes/pixel? */
2359	height *= fontheight (p);
2360
2361	col = attr_bgcol_ec (p, conp);
2362	col &= 0xff;
2363
2364	clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2365			(unsigned short) width, (unsigned short) height,
2366			col, fb_info->currentmode.line_length);
2367
2368	DPRINTK ("EXIT\n");
2369}
2370
2371#endif				/* FBCON_HAS_CFB32 */
2372
2373
2374
2375
2376#ifdef CONFIG_ALL_PPC
2377#define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2378#define PREP_IO_BASE    ((volatile unsigned char *) 0x80000000)
2379static void __init get_prep_addrs (unsigned long *display, unsigned long *registers)
2380{
2381	DPRINTK ("ENTER\n");
2382
2383	*display = PREP_VIDEO_BASE;
2384	*registers = (unsigned long) PREP_IO_BASE;
2385
2386	DPRINTK ("EXIT\n");
2387}
2388
2389#endif				/* CONFIG_ALL_PPC */
2390
2391
2392
2393
2394#ifdef CONFIG_PCI
2395static int release_io_ports = 0;
2396
2397/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2398 * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
2399 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2400 * seem to have. */
2401static unsigned int __init clgen_get_memsize (caddr_t regbase)
2402{
2403	unsigned long mem;
2404	unsigned char SRF;
2405
2406	DPRINTK ("ENTER\n");
2407
2408	SRF = vga_rseq (regbase, CL_SEQRF);
2409	switch ((SRF & 0x18)) {
2410	    case 0x08: mem = 512 * 1024; break;
2411	    case 0x10: mem = 1024 * 1024; break;
2412		/* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2413		   * on the 5430. */
2414	    case 0x18: mem = 2048 * 1024; break;
2415	    default: printk ("CLgenfb: Unknown memory size!\n");
2416		mem = 1024 * 1024;
2417	}
2418	if (SRF & 0x80) {
2419		/* If DRAM bank switching is enabled, there must be twice as much
2420		   * memory installed. (4MB on the 5434) */
2421		mem *= 2;
2422	}
2423	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2424	return mem;
2425
2426	DPRINTK ("EXIT\n");
2427}
2428
2429
2430
2431static struct pci_dev * __init clgen_pci_dev_get (clgen_board_t *btype)
2432{
2433	struct pci_dev *pdev;
2434	int i;
2435
2436	DPRINTK ("ENTER\n");
2437
2438	for (i = 0; i < ARRAY_SIZE(clgen_pci_probe_list); i++) {
2439		pdev = NULL;
2440		while ((pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS,
2441				clgen_pci_probe_list[i].device, pdev)) != NULL) {
2442			if (pci_enable_device(pdev) == 0) {
2443				*btype = clgen_pci_probe_list[i].btype;
2444				DPRINTK ("EXIT, returning pdev=%p\n", pdev);
2445				return pdev;
2446			}
2447		}
2448	}
2449
2450	DPRINTK ("EXIT, returning NULL\n");
2451	return NULL;
2452}
2453
2454
2455
2456
2457static void __init get_pci_addrs (const struct pci_dev *pdev,
2458			   unsigned long *display, unsigned long *registers)
2459{
2460	assert (pdev != NULL);
2461	assert (display != NULL);
2462	assert (registers != NULL);
2463
2464	DPRINTK ("ENTER\n");
2465
2466	*display = 0;
2467	*registers = 0;
2468
2469	/* This is a best-guess for now */
2470
2471	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
2472		*display = pci_resource_start(pdev, 1);
2473		*registers = pci_resource_start(pdev, 0);
2474	} else {
2475		*display = pci_resource_start(pdev, 0);
2476		*registers = pci_resource_start(pdev, 1);
2477	}
2478
2479	assert (*display != 0);
2480
2481	DPRINTK ("EXIT\n");
2482}
2483
2484
2485static void __exit clgen_pci_unmap (struct clgenfb_info *info)
2486{
2487	iounmap (info->fbmem);
2488	release_mem_region(info->fbmem_phys, info->size);
2489
2490
2491	if (release_io_ports)
2492		release_region(0x3C0, 32);
2493}
2494
2495
2496static int __init clgen_pci_setup (struct clgenfb_info *info,
2497				   clgen_board_t *btype)
2498{
2499	struct pci_dev *pdev;
2500	unsigned long board_addr, board_size;
2501
2502	DPRINTK ("ENTER\n");
2503
2504	pdev = clgen_pci_dev_get (btype);
2505	if (!pdev) {
2506		printk (KERN_ERR " Couldn't find PCI device\n");
2507		DPRINTK ("EXIT, returning 1\n");
2508		return 1;
2509	}
2510	DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
2511		 pdev->resource[0].start, *btype);
2512	DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
2513
2514	info->pdev = pdev;
2515
2516	if(isPReP) {
2517		/* Xbh does this, though 0 seems to be the init value */
2518		pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0,
2519			0x00000000);
2520
2521#ifdef CONFIG_ALL_PPC
2522		get_prep_addrs (&board_addr, &info->fbregs_phys);
2523#endif
2524	} else {
2525		DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
2526		get_pci_addrs (pdev, &board_addr, &info->fbregs_phys);
2527	}
2528
2529	DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, info->fbregs_phys);
2530
2531	if(isPReP) {
2532		/* PReP dies if we ioremap the IO registers, but it works w/out... */
2533		info->regs = (char *) info->fbregs_phys;
2534	} else
2535		info->regs = 0;
2536
2537	if (*btype == BT_GD5480) {
2538		board_size = 32 * MB_;
2539	} else {
2540		board_size = clgen_get_memsize (info->regs);
2541	}
2542
2543	if (!request_mem_region(board_addr, board_size, "clgenfb")) {
2544		printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2545		       board_addr);
2546		return -1;
2547	}
2548	if (request_region(0x3C0, 32, "clgenfb"))
2549		release_io_ports = 1;
2550
2551	info->fbmem = ioremap (board_addr, board_size);
2552	info->fbmem_phys = board_addr;
2553	info->size = board_size;
2554
2555	printk (" RAM (%lu kB) at 0x%lx, ", info->size / KB_, board_addr);
2556
2557	printk ("Cirrus Logic chipset on PCI bus\n");
2558
2559	DPRINTK ("EXIT, returning 0\n");
2560	return 0;
2561}
2562#endif				/* CONFIG_PCI */
2563
2564
2565
2566
2567#ifdef CONFIG_ZORRO
2568static int __init clgen_zorro_find (struct zorro_dev **z_o,
2569				    struct zorro_dev **z2_o,
2570				    clgen_board_t *btype, unsigned long *size)
2571{
2572	struct zorro_dev *z = NULL;
2573	int i;
2574
2575	assert (z_o != NULL);
2576	assert (btype != NULL);
2577
2578	for (i = 0; i < ARRAY_SIZE(clgen_zorro_probe_list); i++)
2579		if ((z = zorro_find_device(clgen_zorro_probe_list[i].id, NULL)))
2580			break;
2581
2582	if (z) {
2583		*z_o = z;
2584		if (clgen_zorro_probe_list[i].id2)
2585			*z2_o = zorro_find_device(clgen_zorro_probe_list[i].id2, NULL);
2586		else
2587			*z2_o = NULL;
2588
2589		*btype = clgen_zorro_probe_list[i].btype;
2590		*size = clgen_zorro_probe_list[i].size;
2591
2592		printk (KERN_INFO "clgen: %s board detected; ",
2593			clgen_board_info[*btype].name);
2594
2595		return 0;
2596	}
2597
2598	printk (KERN_NOTICE "clgen: no supported board found.\n");
2599	return -1;
2600}
2601
2602
2603static void __exit clgen_zorro_unmap (struct clgenfb_info *info)
2604{
2605	release_mem_region(info->board_addr, info->board_size);
2606
2607	if (info->btype == BT_PICASSO4) {
2608		iounmap ((void *)info->board_addr);
2609		iounmap ((void *)info->fbmem_phys);
2610	} else {
2611		if (info->board_addr > 0x01000000)
2612			iounmap ((void *)info->board_addr);
2613	}
2614}
2615
2616
2617static int __init clgen_zorro_setup (struct clgenfb_info *info,
2618				     clgen_board_t *btype)
2619{
2620	struct zorro_dev *z = NULL, *z2 = NULL;
2621	unsigned long board_addr, board_size, size;
2622
2623	assert (info != NULL);
2624	assert (btype != NULL);
2625
2626	if (clgen_zorro_find (&z, &z2, btype, &size))
2627		return -1;
2628
2629	assert (z > 0);
2630	assert (z2 >= 0);
2631	assert (*btype != BT_NONE);
2632
2633	info->board_addr = board_addr = z->resource.start;
2634	info->board_size = board_size = z->resource.end-z->resource.start+1;
2635	info->size = size;
2636
2637	if (!request_mem_region(board_addr, board_size, "clgenfb")) {
2638		printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2639		       board_addr);
2640		return -1;
2641	}
2642
2643	printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
2644
2645	if (*btype == BT_PICASSO4) {
2646		printk (" REG at $%lx\n", board_addr + 0x600000);
2647
2648		/* To be precise, for the P4 this is not the */
2649		/* begin of the board, but the begin of RAM. */
2650		/* for P4, map in its address space in 2 chunks (### TEST! ) */
2651		/* (note the ugly hardcoded 16M number) */
2652		info->regs = ioremap (board_addr, 16777216);
2653		DPRINTK ("clgen: Virtual address for board set to: $%p\n", info->regs);
2654		info->regs += 0x600000;
2655		info->fbregs_phys = board_addr + 0x600000;
2656
2657		info->fbmem_phys = board_addr + 16777216;
2658		info->fbmem = ioremap (info->fbmem_phys, 16777216);
2659	} else {
2660		printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
2661
2662		info->fbmem_phys = board_addr;
2663		if (board_addr > 0x01000000)
2664			info->fbmem = ioremap (board_addr, board_size);
2665		else
2666			info->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
2667
2668		/* set address for REG area of board */
2669		info->regs = (caddr_t) ZTWO_VADDR (z2->resource.start);
2670		info->fbregs_phys = z2->resource.start;
2671
2672		DPRINTK ("clgen: Virtual address for board set to: $%p\n", info->regs);
2673	}
2674
2675	printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
2676
2677	return 0;
2678}
2679#endif /* CONFIG_ZORRO */
2680
2681
2682
2683/********************************************************************/
2684/* clgenfb_init() - master initialization function                  */
2685/********************************************************************/
2686int __init clgenfb_init(void)
2687{
2688	int err, j, k;
2689
2690	clgen_board_t btype = BT_NONE;
2691	struct clgenfb_info *fb_info = NULL;
2692
2693	DPRINTK ("ENTER\n");
2694
2695	printk (KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
2696
2697	fb_info = &boards[0];
2698
2699#ifdef CONFIG_PCI
2700	if (clgen_pci_setup (fb_info, &btype)) { /* Also does OF setup */
2701		DPRINTK ("EXIT, returning -ENXIO\n");
2702		return -ENXIO;
2703	}
2704
2705#elif defined(CONFIG_ZORRO)
2706	if (clgen_zorro_setup (fb_info, &btype)) {
2707		DPRINTK ("EXIT, returning -ENXIO\n");
2708		return -ENXIO;
2709	}
2710
2711#else
2712#error This driver requires Zorro or PCI bus.
2713#endif				/* !CONFIG_PCI, !CONFIG_ZORRO */
2714
2715	/* sanity checks */
2716	assert (btype != BT_NONE);
2717	assert (btype == clgen_board_info[btype].btype);
2718
2719	fb_info->btype = btype;
2720
2721	DPRINTK ("clgen: (RAM start set to: 0x%p)\n", fb_info->fbmem);
2722
2723	if (noaccel)
2724	{
2725		printk("clgen: disabling text acceleration support\n");
2726#ifdef FBCON_HAS_CFB8
2727		fbcon_clgen_8.bmove = fbcon_cfb8_bmove;
2728		fbcon_clgen_8.clear = fbcon_cfb8_clear;
2729#endif
2730#ifdef FBCON_HAS_CFB16
2731		fbcon_clgen_16.bmove = fbcon_cfb16_bmove;
2732		fbcon_clgen_16.clear = fbcon_cfb16_clear;
2733#endif
2734#ifdef FBCON_HAS_CFB32
2735		fbcon_clgen_32.bmove = fbcon_cfb32_bmove;
2736		fbcon_clgen_32.clear = fbcon_cfb32_clear;
2737#endif
2738	}
2739
2740	init_vgachip (fb_info);
2741
2742	/* set up a few more things, register framebuffer driver etc */
2743	fb_info->gen.parsize = sizeof (struct clgenfb_par);
2744	fb_info->gen.fbhw = &clgen_hwswitch;
2745
2746	strncpy (fb_info->gen.info.modename, clgen_board_info[btype].name,
2747		 sizeof (fb_info->gen.info.modename));
2748	fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0;
2749
2750	fb_info->gen.info.node = -1;
2751	fb_info->gen.info.fbops = &clgenfb_ops;
2752	fb_info->gen.info.disp = &disp;
2753	fb_info->gen.info.changevar = NULL;
2754	fb_info->gen.info.switch_con = &fbgen_switch;
2755	fb_info->gen.info.updatevar = &fbgen_update_var;
2756	fb_info->gen.info.blank = &fbgen_blank;
2757	fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
2758
2759	for (j = 0; j < 256; j++) {
2760		if (j < 16) {
2761			k = color_table[j];
2762			fb_info->palette[j].red = default_red[k];
2763			fb_info->palette[j].green = default_grn[k];
2764			fb_info->palette[j].blue = default_blu[k];
2765		} else {
2766			fb_info->palette[j].red =
2767			fb_info->palette[j].green =
2768			fb_info->palette[j].blue = j;
2769		}
2770	}
2771
2772	/* now that we know the board has been registered n' stuff, we */
2773	/* can finally initialize it to a default mode */
2774	clgenfb_default = clgenfb_predefined[clgen_def_mode].var;
2775	clgenfb_default.activate = FB_ACTIVATE_NOW;
2776	clgenfb_default.yres_virtual = 480 * 3;		/* for fast scrolling (YPAN-Mode) */
2777	err = fbgen_do_set_var (&clgenfb_default, 1, &fb_info->gen);
2778
2779	if (err) {
2780		DPRINTK ("EXIT, returning -EINVAL\n");
2781		return -EINVAL;
2782	}
2783
2784	disp.var = clgenfb_default;
2785	fbgen_set_disp (-1, &fb_info->gen);
2786	fbgen_install_cmap (0, &fb_info->gen);
2787
2788	err = register_framebuffer (&fb_info->gen.info);
2789	if (err) {
2790		printk (KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err);
2791		DPRINTK ("EXIT, returning -EINVAL\n");
2792		return -EINVAL;
2793	}
2794	DPRINTK ("EXIT, returning 0\n");
2795	return 0;
2796}
2797
2798
2799
2800    /*
2801     *  Cleanup (only needed for module)
2802     */
2803static void __exit clgenfb_cleanup (struct clgenfb_info *info)
2804{
2805	DPRINTK ("ENTER\n");
2806
2807#ifdef CONFIG_ZORRO
2808	switch_monitor (info, 0);
2809
2810	clgen_zorro_unmap (info);
2811#else
2812	clgen_pci_unmap (info);
2813#endif				/* CONFIG_ZORRO */
2814
2815	unregister_framebuffer ((struct fb_info *) info);
2816	printk ("Framebuffer unregistered\n");
2817
2818	DPRINTK ("EXIT\n");
2819}
2820
2821
2822#ifndef MODULE
2823int __init clgenfb_setup(char *options) {
2824	char *this_opt, s[32];
2825	int i;
2826
2827	DPRINTK ("ENTER\n");
2828
2829	if (!options || !*options)
2830		return 0;
2831
2832	for (this_opt = strtok (options, ","); this_opt != NULL;
2833	     this_opt = strtok (NULL, ",")) {
2834		if (!*this_opt) continue;
2835
2836		DPRINTK("clgenfb_setup: option '%s'\n", this_opt);
2837
2838		for (i = 0; i < NUM_TOTAL_MODES; i++) {
2839			sprintf (s, "mode:%s", clgenfb_predefined[i].name);
2840			if (strcmp (this_opt, s) == 0)
2841				clgen_def_mode = i;
2842		}
2843		if (!strcmp(this_opt, "noaccel"))
2844			noaccel = 1;
2845	}
2846	return 0;
2847}
2848#endif
2849
2850
2851    /*
2852     *  Modularization
2853     */
2854
2855MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>");
2856MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2857MODULE_LICENSE("GPL");
2858
2859static void __exit clgenfb_exit (void)
2860{
2861	DPRINTK ("ENTER\n");
2862
2863	clgenfb_cleanup (&boards[0]);
2864
2865	DPRINTK ("EXIT\n");
2866}
2867
2868#ifdef MODULE
2869module_init(clgenfb_init);
2870#endif
2871module_exit(clgenfb_exit);
2872
2873
2874/**********************************************************************/
2875/* about the following functions - I have used the same names for the */
2876/* functions as Markus Wild did in his Retina driver for NetBSD as    */
2877/* they just made sense for this purpose. Apart from that, I wrote    */
2878/* these functions myself.                                            */
2879/**********************************************************************/
2880
2881/*** WGen() - write into one of the external/general registers ***/
2882static void WGen (const struct clgenfb_info *fb_info,
2883		  int regnum, unsigned char val)
2884{
2885	unsigned long regofs = 0;
2886
2887	if (fb_info->btype == BT_PICASSO) {
2888		/* Picasso II specific hack */
2889/*              if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2890		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2891			regofs = 0xfff;
2892	}
2893
2894	vga_w (fb_info->regs, regofs + regnum, val);
2895}
2896
2897/*** RGen() - read out one of the external/general registers ***/
2898static unsigned char RGen (const struct clgenfb_info *fb_info, int regnum)
2899{
2900	unsigned long regofs = 0;
2901
2902	if (fb_info->btype == BT_PICASSO) {
2903		/* Picasso II specific hack */
2904/*              if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2905		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2906			regofs = 0xfff;
2907	}
2908
2909	return vga_r (fb_info->regs, regofs + regnum);
2910}
2911
2912/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2913static void AttrOn (const struct clgenfb_info *fb_info)
2914{
2915	assert (fb_info != NULL);
2916
2917	DPRINTK ("ENTER\n");
2918
2919	if (vga_rcrt (fb_info->regs, CL_CRT24) & 0x80) {
2920		/* if we're just in "write value" mode, write back the */
2921		/* same value as before to not modify anything */
2922		vga_w (fb_info->regs, VGA_ATT_IW,
2923		       vga_r (fb_info->regs, VGA_ATT_R));
2924	}
2925	/* turn on video bit */
2926/*      vga_w (fb_info->regs, VGA_ATT_IW, 0x20); */
2927	vga_w (fb_info->regs, VGA_ATT_IW, 0x33);
2928
2929	/* dummy write on Reg0 to be on "write index" mode next time */
2930	vga_w (fb_info->regs, VGA_ATT_IW, 0x00);
2931
2932	DPRINTK ("EXIT\n");
2933}
2934
2935/*** WHDR() - write into the Hidden DAC register ***/
2936/* as the HDR is the only extension register that requires special treatment
2937 * (the other extension registers are accessible just like the "ordinary"
2938 * registers of their functional group) here is a specialized routine for
2939 * accessing the HDR
2940 */
2941static void WHDR (const struct clgenfb_info *fb_info, unsigned char val)
2942{
2943	unsigned char dummy;
2944
2945	if (fb_info->btype == BT_PICASSO) {
2946		/* Klaus' hint for correct access to HDR on some boards */
2947		/* first write 0 to pixel mask (3c6) */
2948		WGen (fb_info, VGA_PEL_MSK, 0x00);
2949		udelay (200);
2950		/* next read dummy from pixel address (3c8) */
2951		dummy = RGen (fb_info, VGA_PEL_IW);
2952		udelay (200);
2953	}
2954	/* now do the usual stuff to access the HDR */
2955
2956	dummy = RGen (fb_info, VGA_PEL_MSK);
2957	udelay (200);
2958	dummy = RGen (fb_info, VGA_PEL_MSK);
2959	udelay (200);
2960	dummy = RGen (fb_info, VGA_PEL_MSK);
2961	udelay (200);
2962	dummy = RGen (fb_info, VGA_PEL_MSK);
2963	udelay (200);
2964
2965	WGen (fb_info, VGA_PEL_MSK, val);
2966	udelay (200);
2967
2968	if (fb_info->btype == BT_PICASSO) {
2969		/* now first reset HDR access counter */
2970		dummy = RGen (fb_info, VGA_PEL_IW);
2971		udelay (200);
2972
2973		/* and at the end, restore the mask value */
2974		/* ## is this mask always 0xff? */
2975		WGen (fb_info, VGA_PEL_MSK, 0xff);
2976		udelay (200);
2977	}
2978}
2979
2980
2981/*** WSFR() - write to the "special function register" (SFR) ***/
2982static void WSFR (struct clgenfb_info *fb_info, unsigned char val)
2983{
2984#ifdef CONFIG_ZORRO
2985	assert (fb_info->regs != NULL);
2986	fb_info->SFR = val;
2987	z_writeb (val, fb_info->regs + 0x8000);
2988#endif
2989}
2990
2991/* The Picasso has a second register for switching the monitor bit */
2992static void WSFR2 (struct clgenfb_info *fb_info, unsigned char val)
2993{
2994#ifdef CONFIG_ZORRO
2995	/* writing an arbitrary value to this one causes the monitor switcher */
2996	/* to flip to Amiga display */
2997	assert (fb_info->regs != NULL);
2998	fb_info->SFR = val;
2999	z_writeb (val, fb_info->regs + 0x9000);
3000#endif
3001}
3002
3003
3004/*** WClut - set CLUT entry (range: 0..63) ***/
3005static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
3006	    unsigned char green, unsigned char blue)
3007{
3008	unsigned int data = VGA_PEL_D;
3009
3010	/* address write mode register is not translated.. */
3011	vga_w (fb_info->regs, VGA_PEL_IW, regnum);
3012
3013	if (fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4 ||
3014	    fb_info->btype == BT_ALPINE || fb_info->btype == BT_GD5480) {
3015		/* but DAC data register IS, at least for Picasso II */
3016		if (fb_info->btype == BT_PICASSO)
3017			data += 0xfff;
3018		vga_w (fb_info->regs, data, red);
3019		vga_w (fb_info->regs, data, green);
3020		vga_w (fb_info->regs, data, blue);
3021	} else {
3022		vga_w (fb_info->regs, data, blue);
3023		vga_w (fb_info->regs, data, green);
3024		vga_w (fb_info->regs, data, red);
3025	}
3026}
3027
3028
3029
3030
3031/*******************************************************************
3032	clgen_WaitBLT()
3033
3034	Wait for the BitBLT engine to complete a possible earlier job
3035*********************************************************************/
3036
3037static inline void clgen_WaitBLT (caddr_t regbase)
3038{
3039	/* now busy-wait until we're done */
3040	while (vga_rgfx (regbase, CL_GR31) & 0x08)
3041		/* do nothing */ ;
3042}
3043
3044/*******************************************************************
3045	clgen_BitBLT()
3046
3047	perform accelerated "scrolling"
3048********************************************************************/
3049
3050static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury, u_short destx, u_short desty,
3051		   u_short width, u_short height, u_short line_length)
3052{
3053	u_short nwidth, nheight;
3054	u_long nsrc, ndest;
3055	u_char bltmode;
3056
3057	DPRINTK ("ENTER\n");
3058
3059	nwidth = width - 1;
3060	nheight = height - 1;
3061
3062	bltmode = 0x00;
3063	/* if source adr < dest addr, do the Blt backwards */
3064	if (cury <= desty) {
3065		if (cury == desty) {
3066			/* if src and dest are on the same line, check x */
3067			if (curx < destx)
3068				bltmode |= 0x01;
3069		} else
3070			bltmode |= 0x01;
3071	}
3072	if (!bltmode) {
3073		/* standard case: forward blitting */
3074		nsrc = (cury * line_length) + curx;
3075		ndest = (desty * line_length) + destx;
3076	} else {
3077		/* this means start addresses are at the end, counting backwards */
3078		nsrc = cury * line_length + curx + nheight * line_length + nwidth;
3079		ndest = desty * line_length + destx + nheight * line_length + nwidth;
3080	}
3081
3082        clgen_WaitBLT(regbase);
3083
3084	/*
3085	   run-down of registers to be programmed:
3086	   destination pitch
3087	   source pitch
3088	   BLT width/height
3089	   source start
3090	   destination start
3091	   BLT mode
3092	   BLT ROP
3093	   VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
3094	   start/stop
3095	 */
3096
3097	/* pitch: set to line_length */
3098	vga_wgfx (regbase, CL_GR24, line_length & 0xff);	/* dest pitch low */
3099	vga_wgfx (regbase, CL_GR25, (line_length >> 8));	/* dest pitch hi */
3100	vga_wgfx (regbase, CL_GR26, line_length & 0xff);	/* source pitch low */
3101	vga_wgfx (regbase, CL_GR27, (line_length >> 8));	/* source pitch hi */
3102
3103	/* BLT width: actual number of pixels - 1 */
3104	vga_wgfx (regbase, CL_GR20, nwidth & 0xff);	/* BLT width low */
3105	vga_wgfx (regbase, CL_GR21, (nwidth >> 8));	/* BLT width hi */
3106
3107	/* BLT height: actual number of lines -1 */
3108	vga_wgfx (regbase, CL_GR22, nheight & 0xff);	/* BLT height low */
3109	vga_wgfx (regbase, CL_GR23, (nheight >> 8));	/* BLT width hi */
3110
3111	/* BLT destination */
3112	vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff));	/* BLT dest low */
3113	vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8));	/* BLT dest mid */
3114	vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16));	/* BLT dest hi */
3115
3116	/* BLT source */
3117	vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff));	/* BLT src low */
3118	vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8));		/* BLT src mid */
3119	vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16));	/* BLT src hi */
3120
3121	/* BLT mode */
3122	vga_wgfx (regbase, CL_GR30, bltmode);	/* BLT mode */
3123
3124	/* BLT ROP: SrcCopy */
3125	vga_wgfx (regbase, CL_GR32, 0x0d);		/* BLT ROP */
3126
3127	/* and finally: GO! */
3128	vga_wgfx (regbase, CL_GR31, 0x02);		/* BLT Start/status */
3129
3130	DPRINTK ("EXIT\n");
3131}
3132
3133
3134/*******************************************************************
3135	clgen_RectFill()
3136
3137	perform accelerated rectangle fill
3138********************************************************************/
3139
3140static void clgen_RectFill (struct clgenfb_info *fb_info,
3141		     u_short x, u_short y, u_short width, u_short height,
3142		     u_char color, u_short line_length)
3143{
3144	u_short nwidth, nheight;
3145	u_long ndest;
3146	u_char op;
3147
3148	DPRINTK ("ENTER\n");
3149
3150	nwidth = width - 1;
3151	nheight = height - 1;
3152
3153	ndest = (y * line_length) + x;
3154
3155        clgen_WaitBLT(fb_info->regs);
3156
3157	/* pitch: set to line_length */
3158	vga_wgfx (fb_info->regs, CL_GR24, line_length & 0xff);	/* dest pitch low */
3159	vga_wgfx (fb_info->regs, CL_GR25, (line_length >> 8));	/* dest pitch hi */
3160	vga_wgfx (fb_info->regs, CL_GR26, line_length & 0xff);	/* source pitch low */
3161	vga_wgfx (fb_info->regs, CL_GR27, (line_length >> 8));	/* source pitch hi */
3162
3163	/* BLT width: actual number of pixels - 1 */
3164	vga_wgfx (fb_info->regs, CL_GR20, nwidth & 0xff);	/* BLT width low */
3165	vga_wgfx (fb_info->regs, CL_GR21, (nwidth >> 8));	/* BLT width hi */
3166
3167	/* BLT height: actual number of lines -1 */
3168	vga_wgfx (fb_info->regs, CL_GR22, nheight & 0xff);		/* BLT height low */
3169	vga_wgfx (fb_info->regs, CL_GR23, (nheight >> 8));		/* BLT width hi */
3170
3171	/* BLT destination */
3172	vga_wgfx (fb_info->regs, CL_GR28, (u_char) (ndest & 0xff));	/* BLT dest low */
3173	vga_wgfx (fb_info->regs, CL_GR29, (u_char) (ndest >> 8));	/* BLT dest mid */
3174	vga_wgfx (fb_info->regs, CL_GR2A, (u_char) (ndest >> 16));		/* BLT dest hi */
3175
3176	/* BLT source: set to 0 (is a dummy here anyway) */
3177	vga_wgfx (fb_info->regs, CL_GR2C, 0x00);	/* BLT src low */
3178	vga_wgfx (fb_info->regs, CL_GR2D, 0x00);	/* BLT src mid */
3179	vga_wgfx (fb_info->regs, CL_GR2E, 0x00);	/* BLT src hi */
3180
3181	/* This is a ColorExpand Blt, using the */
3182	/* same color for foreground and background */
3183	vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, color);	/* foreground color */
3184	vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, color);	/* background color */
3185
3186	op = 0xc0;
3187	if (fb_info->currentmode.var.bits_per_pixel == 16) {
3188		vga_wgfx (fb_info->regs, CL_GR10, color);	/* foreground color */
3189		vga_wgfx (fb_info->regs, CL_GR11, color);	/* background color */
3190		op = 0x50;
3191		op = 0xd0;
3192	} else if (fb_info->currentmode.var.bits_per_pixel == 32) {
3193		vga_wgfx (fb_info->regs, CL_GR10, color);	/* foreground color */
3194		vga_wgfx (fb_info->regs, CL_GR11, color);	/* background color */
3195		vga_wgfx (fb_info->regs, CL_GR12, color);	/* foreground color */
3196		vga_wgfx (fb_info->regs, CL_GR13, color);	/* background color */
3197		vga_wgfx (fb_info->regs, CL_GR14, 0);	/* foreground color */
3198		vga_wgfx (fb_info->regs, CL_GR15, 0);	/* background color */
3199		op = 0x50;
3200		op = 0xf0;
3201	}
3202	/* BLT mode: color expand, Enable 8x8 copy (faster?) */
3203	vga_wgfx (fb_info->regs, CL_GR30, op);	/* BLT mode */
3204
3205	/* BLT ROP: SrcCopy */
3206	vga_wgfx (fb_info->regs, CL_GR32, 0x0d);	/* BLT ROP */
3207
3208	/* and finally: GO! */
3209	vga_wgfx (fb_info->regs, CL_GR31, 0x02);	/* BLT Start/status */
3210
3211	DPRINTK ("EXIT\n");
3212}
3213
3214
3215/**************************************************************************
3216 * bestclock() - determine closest possible clock lower(?) than the
3217 * desired pixel clock
3218 **************************************************************************/
3219static void bestclock (long freq, long *best, long *nom,
3220		       long *den, long *div, long maxfreq)
3221{
3222	long n, h, d, f;
3223
3224	assert (best != NULL);
3225	assert (nom != NULL);
3226	assert (den != NULL);
3227	assert (div != NULL);
3228	assert (maxfreq > 0);
3229
3230	*nom = 0;
3231	*den = 0;
3232	*div = 0;
3233
3234	DPRINTK ("ENTER\n");
3235
3236	if (freq < 8000)
3237		freq = 8000;
3238
3239	if (freq > maxfreq)
3240		freq = maxfreq;
3241
3242	*best = 0;
3243	f = freq * 10;
3244
3245	for (n = 32; n < 128; n++) {
3246		d = (143181 * n) / f;
3247		if ((d >= 7) && (d <= 63)) {
3248			if (d > 31)
3249				d = (d / 2) * 2;
3250			h = (14318 * n) / d;
3251			if (abs (h - freq) < abs (*best - freq)) {
3252				*best = h;
3253				*nom = n;
3254				if (d < 32) {
3255					*den = d;
3256					*div = 0;
3257				} else {
3258					*den = d / 2;
3259					*div = 1;
3260				}
3261			}
3262		}
3263		d = ((143181 * n) + f - 1) / f;
3264		if ((d >= 7) && (d <= 63)) {
3265			if (d > 31)
3266				d = (d / 2) * 2;
3267			h = (14318 * n) / d;
3268			if (abs (h - freq) < abs (*best - freq)) {
3269				*best = h;
3270				*nom = n;
3271				if (d < 32) {
3272					*den = d;
3273					*div = 0;
3274				} else {
3275					*den = d / 2;
3276					*div = 1;
3277				}
3278			}
3279		}
3280	}
3281
3282	DPRINTK ("Best possible values for given frequency:\n");
3283	DPRINTK ("        best: %ld kHz  nom: %ld  den: %ld  div: %ld\n",
3284		 freq, *nom, *den, *div);
3285
3286	DPRINTK ("EXIT\n");
3287}
3288
3289
3290/* -------------------------------------------------------------------------
3291 *
3292 * debugging functions
3293 *
3294 * -------------------------------------------------------------------------
3295 */
3296
3297#ifdef CLGEN_DEBUG
3298
3299/**
3300 * clgen_dbg_print_byte
3301 * @name: name associated with byte value to be displayed
3302 * @val: byte value to be displayed
3303 *
3304 * DESCRIPTION:
3305 * Display an indented string, along with a hexidecimal byte value, and
3306 * its decoded bits.  Bits 7 through 0 are listed in left-to-right
3307 * order.
3308 */
3309
3310static
3311void clgen_dbg_print_byte (const char *name, unsigned char val)
3312{
3313	DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3314		 name, val,
3315		 val & 0x80 ? '1' : '0',
3316		 val & 0x40 ? '1' : '0',
3317		 val & 0x20 ? '1' : '0',
3318		 val & 0x10 ? '1' : '0',
3319		 val & 0x08 ? '1' : '0',
3320		 val & 0x04 ? '1' : '0',
3321		 val & 0x02 ? '1' : '0',
3322		 val & 0x01 ? '1' : '0');
3323}
3324
3325
3326/**
3327 * clgen_dbg_print_regs
3328 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3329 * @reg_class: type of registers to read: %CRT, or %SEQ
3330 *
3331 * DESCRIPTION:
3332 * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
3333 * old-style I/O ports are queried for information, otherwise MMIO is
3334 * used at the given @base address to query the information.
3335 */
3336
3337static
3338void clgen_dbg_print_regs (caddr_t regbase, clgen_dbg_reg_class_t reg_class,...)
3339{
3340	va_list list;
3341	unsigned char val = 0;
3342	unsigned reg;
3343	char *name;
3344
3345	va_start (list, reg_class);
3346
3347	name = va_arg (list, char *);
3348	while (name != NULL) {
3349		reg = va_arg (list, int);
3350
3351		switch (reg_class) {
3352		case CRT:
3353			val = vga_rcrt (regbase, (unsigned char) reg);
3354			break;
3355		case SEQ:
3356			val = vga_rseq (regbase, (unsigned char) reg);
3357			break;
3358		default:
3359			/* should never occur */
3360			assert (FALSE);
3361			break;
3362		}
3363
3364		clgen_dbg_print_byte (name, val);
3365
3366		name = va_arg (list, char *);
3367	}
3368
3369	va_end (list);
3370}
3371
3372
3373/**
3374 * clgen_dump
3375 * @clgeninfo:
3376 *
3377 * DESCRIPTION:
3378 */
3379
3380static
3381void clgen_dump (void)
3382{
3383	clgen_dbg_reg_dump (NULL);
3384}
3385
3386
3387/**
3388 * clgen_dbg_reg_dump
3389 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3390 *
3391 * DESCRIPTION:
3392 * Dumps a list of interesting VGA and CLGEN registers.  If @base is %NULL,
3393 * old-style I/O ports are queried for information, otherwise MMIO is
3394 * used at the given @base address to query the information.
3395 */
3396
3397static
3398void clgen_dbg_reg_dump (caddr_t regbase)
3399{
3400	DPRINTK ("CLGEN VGA CRTC register dump:\n");
3401
3402	clgen_dbg_print_regs (regbase, CRT,
3403			   "CR00", 0x00,
3404			   "CR01", 0x01,
3405			   "CR02", 0x02,
3406			   "CR03", 0x03,
3407			   "CR04", 0x04,
3408			   "CR05", 0x05,
3409			   "CR06", 0x06,
3410			   "CR07", 0x07,
3411			   "CR08", 0x08,
3412			   "CR09", 0x09,
3413			   "CR0A", 0x0A,
3414			   "CR0B", 0x0B,
3415			   "CR0C", 0x0C,
3416			   "CR0D", 0x0D,
3417			   "CR0E", 0x0E,
3418			   "CR0F", 0x0F,
3419			   "CR10", 0x10,
3420			   "CR11", 0x11,
3421			   "CR12", 0x12,
3422			   "CR13", 0x13,
3423			   "CR14", 0x14,
3424			   "CR15", 0x15,
3425			   "CR16", 0x16,
3426			   "CR17", 0x17,
3427			   "CR18", 0x18,
3428			   "CR22", 0x22,
3429			   "CR24", 0x24,
3430			   "CR26", 0x26,
3431			   "CR2D", 0x2D,
3432			   "CR2E", 0x2E,
3433			   "CR2F", 0x2F,
3434			   "CR30", 0x30,
3435			   "CR31", 0x31,
3436			   "CR32", 0x32,
3437			   "CR33", 0x33,
3438			   "CR34", 0x34,
3439			   "CR35", 0x35,
3440			   "CR36", 0x36,
3441			   "CR37", 0x37,
3442			   "CR38", 0x38,
3443			   "CR39", 0x39,
3444			   "CR3A", 0x3A,
3445			   "CR3B", 0x3B,
3446			   "CR3C", 0x3C,
3447			   "CR3D", 0x3D,
3448			   "CR3E", 0x3E,
3449			   "CR3F", 0x3F,
3450			   NULL);
3451
3452	DPRINTK ("\n");
3453
3454	DPRINTK ("CLGEN VGA SEQ register dump:\n");
3455
3456	clgen_dbg_print_regs (regbase, SEQ,
3457			   "SR00", 0x00,
3458			   "SR01", 0x01,
3459			   "SR02", 0x02,
3460			   "SR03", 0x03,
3461			   "SR04", 0x04,
3462			   "SR08", 0x08,
3463			   "SR09", 0x09,
3464			   "SR0A", 0x0A,
3465			   "SR0B", 0x0B,
3466			   "SR0D", 0x0D,
3467			   "SR10", 0x10,
3468			   "SR11", 0x11,
3469			   "SR12", 0x12,
3470			   "SR13", 0x13,
3471			   "SR14", 0x14,
3472			   "SR15", 0x15,
3473			   "SR16", 0x16,
3474			   "SR17", 0x17,
3475			   "SR18", 0x18,
3476			   "SR19", 0x19,
3477			   "SR1A", 0x1A,
3478			   "SR1B", 0x1B,
3479			   "SR1C", 0x1C,
3480			   "SR1D", 0x1D,
3481			   "SR1E", 0x1E,
3482			   "SR1F", 0x1F,
3483			   NULL);
3484
3485	DPRINTK ("\n");
3486}
3487
3488#endif				/* CLGEN_DEBUG */
3489
3490