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