blob: ebb8ddb0095a4ede6a08794a35063b861fc01d7a [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>
Krzysztof Helt8503df62007-10-16 01:29:08 -070062#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
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/*****************************************************************
71 *
72 * debugging and utility macros
73 *
74 */
75
76/* enable debug output? */
77/* #define CIRRUSFB_DEBUG 1 */
78
79/* disable runtime assertions? */
80/* #define CIRRUSFB_NDEBUG */
81
82/* debug output */
83#ifdef CIRRUSFB_DEBUG
Krzysztof Helt8503df62007-10-16 01:29:08 -070084#define DPRINTK(fmt, args...) \
85 printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#else
87#define DPRINTK(fmt, args...)
88#endif
89
90/* debugging assertions */
91#ifndef CIRRUSFB_NDEBUG
92#define assert(expr) \
Krzysztof Helt8503df62007-10-16 01:29:08 -070093 if (!(expr)) { \
94 printk("Assertion failed! %s,%s,%s,line=%d\n", \
95 #expr, __FILE__, __FUNCTION__, __LINE__); \
96 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070097#else
98#define assert(expr)
99#endif
100
Krzysztof Helt8503df62007-10-16 01:29:08 -0700101#define MB_ (1024 * 1024)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102#define KB_ (1024)
103
104#define MAX_NUM_BOARDS 7
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/*****************************************************************
107 *
108 * chipset information
109 *
110 */
111
112/* board types */
Krzysztof Helt7345de32007-10-16 01:29:11 -0700113enum cirrus_board {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 BT_NONE = 0,
115 BT_SD64,
116 BT_PICCOLO,
117 BT_PICASSO,
118 BT_SPECTRUM,
119 BT_PICASSO4, /* GD5446 */
120 BT_ALPINE, /* GD543x/4x */
121 BT_GD5480,
122 BT_LAGUNA, /* GD546x */
Krzysztof Helt7345de32007-10-16 01:29:11 -0700123};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125/*
126 * per-board-type information, used for enumerating and abstracting
127 * chip-specific information
Krzysztof Helt7345de32007-10-16 01:29:11 -0700128 * NOTE: MUST be in the same order as enum cirrus_board in order to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 * use direct indexing on this array
130 * NOTE: '__initdata' cannot be used as some of this info
131 * is required at runtime. Maybe separate into an init-only and
132 * a run-time table?
133 */
134static const struct cirrusfb_board_info_rec {
135 char *name; /* ASCII name of chipset */
136 long maxclock[5]; /* maximum video clock */
137 /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
Richard Knutssonc930faa2007-05-08 00:38:29 -0700138 bool init_sr07 : 1; /* init SR07 during init_vgachip() */
139 bool init_sr1f : 1; /* write SR1F during init_vgachip() */
Krzysztof Helt8503df62007-10-16 01:29:08 -0700140 /* construct bit 19 of screen start address */
141 bool scrn_start_bit19 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 /* initial SR07 value, then for each mode */
144 unsigned char sr07;
145 unsigned char sr07_1bpp;
146 unsigned char sr07_1bpp_mux;
147 unsigned char sr07_8bpp;
148 unsigned char sr07_8bpp_mux;
149
150 unsigned char sr1f; /* SR1F VGA initial register value */
151} cirrusfb_board_info[] = {
152 [BT_SD64] = {
153 .name = "CL SD64",
154 .maxclock = {
155 /* guess */
156 /* the SD64/P4 have a higher max. videoclock */
157 140000, 140000, 140000, 140000, 140000,
158 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700159 .init_sr07 = true,
160 .init_sr1f = true,
161 .scrn_start_bit19 = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 .sr07 = 0xF0,
163 .sr07_1bpp = 0xF0,
164 .sr07_8bpp = 0xF1,
165 .sr1f = 0x20
166 },
167 [BT_PICCOLO] = {
168 .name = "CL Piccolo",
169 .maxclock = {
170 /* guess */
171 90000, 90000, 90000, 90000, 90000
172 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700173 .init_sr07 = true,
174 .init_sr1f = true,
175 .scrn_start_bit19 = false,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 .sr07 = 0x80,
177 .sr07_1bpp = 0x80,
178 .sr07_8bpp = 0x81,
179 .sr1f = 0x22
180 },
181 [BT_PICASSO] = {
182 .name = "CL Picasso",
183 .maxclock = {
184 /* guess */
185 90000, 90000, 90000, 90000, 90000
186 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700187 .init_sr07 = true,
188 .init_sr1f = true,
189 .scrn_start_bit19 = false,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 .sr07 = 0x20,
191 .sr07_1bpp = 0x20,
192 .sr07_8bpp = 0x21,
193 .sr1f = 0x22
194 },
195 [BT_SPECTRUM] = {
196 .name = "CL Spectrum",
197 .maxclock = {
198 /* guess */
199 90000, 90000, 90000, 90000, 90000
200 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700201 .init_sr07 = true,
202 .init_sr1f = true,
203 .scrn_start_bit19 = false,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 .sr07 = 0x80,
205 .sr07_1bpp = 0x80,
206 .sr07_8bpp = 0x81,
207 .sr1f = 0x22
208 },
209 [BT_PICASSO4] = {
210 .name = "CL Picasso4",
211 .maxclock = {
212 135100, 135100, 85500, 85500, 0
213 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700214 .init_sr07 = true,
215 .init_sr1f = false,
216 .scrn_start_bit19 = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 .sr07 = 0x20,
218 .sr07_1bpp = 0x20,
219 .sr07_8bpp = 0x21,
220 .sr1f = 0
221 },
222 [BT_ALPINE] = {
223 .name = "CL Alpine",
224 .maxclock = {
225 /* for the GD5430. GD5446 can do more... */
226 85500, 85500, 50000, 28500, 0
227 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700228 .init_sr07 = true,
229 .init_sr1f = true,
230 .scrn_start_bit19 = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 .sr07 = 0xA0,
232 .sr07_1bpp = 0xA1,
233 .sr07_1bpp_mux = 0xA7,
234 .sr07_8bpp = 0xA1,
235 .sr07_8bpp_mux = 0xA7,
236 .sr1f = 0x1C
237 },
238 [BT_GD5480] = {
239 .name = "CL GD5480",
240 .maxclock = {
241 135100, 200000, 200000, 135100, 135100
242 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700243 .init_sr07 = true,
244 .init_sr1f = true,
245 .scrn_start_bit19 = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 .sr07 = 0x10,
247 .sr07_1bpp = 0x11,
248 .sr07_8bpp = 0x11,
249 .sr1f = 0x1C
250 },
251 [BT_LAGUNA] = {
252 .name = "CL Laguna",
253 .maxclock = {
254 /* guess */
255 135100, 135100, 135100, 135100, 135100,
256 },
Richard Knutssonc930faa2007-05-08 00:38:29 -0700257 .init_sr07 = false,
258 .init_sr1f = false,
259 .scrn_start_bit19 = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
261};
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263#ifdef CONFIG_PCI
264#define CHIP(id, btype) \
Grant Coady41538122005-09-29 10:40:52 +1000265 { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267static struct pci_device_id cirrusfb_pci_table[] = {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700268 CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
269 CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE),
270 CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE),
271 CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
272 CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
273 CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
274 CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
275 CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
276 CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
277 CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
278 CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 { 0, }
280};
281MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
282#undef CHIP
283#endif /* CONFIG_PCI */
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285#ifdef CONFIG_ZORRO
286static const struct zorro_device_id cirrusfb_zorro_table[] = {
287 {
288 .id = ZORRO_PROD_HELFRICH_SD64_RAM,
289 .driver_data = BT_SD64,
290 }, {
291 .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
292 .driver_data = BT_PICCOLO,
293 }, {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700294 .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 .driver_data = BT_PICASSO,
296 }, {
297 .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
298 .driver_data = BT_SPECTRUM,
299 }, {
300 .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
301 .driver_data = BT_PICASSO4,
302 },
303 { 0 }
304};
305
306static const struct {
307 zorro_id id2;
308 unsigned long size;
309} cirrusfb_zorro_table2[] = {
310 [BT_SD64] = {
311 .id2 = ZORRO_PROD_HELFRICH_SD64_REG,
312 .size = 0x400000
313 },
314 [BT_PICCOLO] = {
315 .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG,
316 .size = 0x200000
317 },
318 [BT_PICASSO] = {
319 .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
320 .size = 0x200000
321 },
322 [BT_SPECTRUM] = {
323 .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
324 .size = 0x200000
325 },
326 [BT_PICASSO4] = {
327 .id2 = 0,
328 .size = 0x400000
329 }
330};
331#endif /* CONFIG_ZORRO */
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333struct cirrusfb_regs {
334 __u32 line_length; /* in BYTES! */
335 __u32 visual;
336 __u32 type;
337
338 long freq;
339 long nom;
340 long den;
341 long div;
342 long multiplexing;
343 long mclk;
344 long divMCLK;
345
346 long HorizRes; /* The x resolution in pixel */
347 long HorizTotal;
348 long HorizDispEnd;
349 long HorizBlankStart;
350 long HorizBlankEnd;
351 long HorizSyncStart;
352 long HorizSyncEnd;
353
354 long VertRes; /* the physical y resolution in scanlines */
355 long VertTotal;
356 long VertDispEnd;
357 long VertSyncStart;
358 long VertSyncEnd;
359 long VertBlankStart;
360 long VertBlankEnd;
361};
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363#ifdef CIRRUSFB_DEBUG
Krzysztof Helt7345de32007-10-16 01:29:11 -0700364enum cirrusfb_dbg_reg_class {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700365 CRT,
366 SEQ
Krzysztof Helt7345de32007-10-16 01:29:11 -0700367};
Krzysztof Helt8503df62007-10-16 01:29:08 -0700368#endif /* CIRRUSFB_DEBUG */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
370/* info about board */
371struct cirrusfb_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 u8 __iomem *regbase;
Krzysztof Helt7345de32007-10-16 01:29:11 -0700373 enum cirrus_board btype;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 unsigned char SFR; /* Shadow of special function register */
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 struct cirrusfb_regs currentmode;
377 int blank_mode;
378
Antonino A. Daplas49d5c7b2005-11-29 19:34:43 -0800379 u32 pseudo_palette[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381#ifdef CONFIG_ZORRO
382 struct zorro_dev *zdev;
383#endif
384#ifdef CONFIG_PCI
385 struct pci_dev *pdev;
386#endif
Krzysztof Helt9199ec52007-10-16 01:29:12 -0700387 void (*unmap)(struct fb_info *info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388};
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390static unsigned cirrusfb_def_mode = 1;
Krzysztof Helt8503df62007-10-16 01:29:08 -0700391static int noaccel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393/*
394 * Predefined Video Modes
395 */
396
397static const struct {
398 const char *name;
399 struct fb_var_screeninfo var;
400} cirrusfb_predefined[] = {
401 {
402 /* autodetect mode */
403 .name = "Autodetect",
404 }, {
405 /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
406 .name = "640x480",
407 .var = {
408 .xres = 640,
409 .yres = 480,
410 .xres_virtual = 640,
411 .yres_virtual = 480,
412 .bits_per_pixel = 8,
413 .red = { .length = 8 },
414 .green = { .length = 8 },
415 .blue = { .length = 8 },
416 .width = -1,
417 .height = -1,
418 .pixclock = 40000,
419 .left_margin = 48,
420 .right_margin = 16,
421 .upper_margin = 32,
422 .lower_margin = 8,
423 .hsync_len = 96,
424 .vsync_len = 4,
Krzysztof Helt8503df62007-10-16 01:29:08 -0700425 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 .vmode = FB_VMODE_NONINTERLACED
427 }
428 }, {
429 /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
430 .name = "800x600",
431 .var = {
432 .xres = 800,
433 .yres = 600,
434 .xres_virtual = 800,
435 .yres_virtual = 600,
436 .bits_per_pixel = 8,
437 .red = { .length = 8 },
438 .green = { .length = 8 },
439 .blue = { .length = 8 },
440 .width = -1,
441 .height = -1,
442 .pixclock = 20000,
443 .left_margin = 128,
444 .right_margin = 16,
445 .upper_margin = 24,
446 .lower_margin = 2,
447 .hsync_len = 96,
448 .vsync_len = 6,
449 .vmode = FB_VMODE_NONINTERLACED
450 }
451 }, {
452 /*
453 * Modeline from XF86Config:
454 * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
455 */
456 /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
457 .name = "1024x768",
458 .var = {
459 .xres = 1024,
460 .yres = 768,
461 .xres_virtual = 1024,
462 .yres_virtual = 768,
463 .bits_per_pixel = 8,
464 .red = { .length = 8 },
465 .green = { .length = 8 },
466 .blue = { .length = 8 },
467 .width = -1,
468 .height = -1,
469 .pixclock = 12500,
470 .left_margin = 144,
471 .right_margin = 32,
472 .upper_margin = 30,
473 .lower_margin = 2,
474 .hsync_len = 192,
475 .vsync_len = 6,
476 .vmode = FB_VMODE_NONINTERLACED
477 }
478 }
479};
480
481#define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined)
482
483/****************************************************************************/
484/**** BEGIN PROTOTYPES ******************************************************/
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486/*--- Interface used by the world ------------------------------------------*/
Krzysztof Helt8503df62007-10-16 01:29:08 -0700487static int cirrusfb_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488#ifndef MODULE
Krzysztof Helt8503df62007-10-16 01:29:08 -0700489static int cirrusfb_setup(char *options);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#endif
491
Krzysztof Helt8503df62007-10-16 01:29:08 -0700492static int cirrusfb_open(struct fb_info *info, int user);
493static int cirrusfb_release(struct fb_info *info, int user);
494static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
495 unsigned blue, unsigned transp,
496 struct fb_info *info);
497static int cirrusfb_check_var(struct fb_var_screeninfo *var,
498 struct fb_info *info);
499static int cirrusfb_set_par(struct fb_info *info);
500static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
501 struct fb_info *info);
502static int cirrusfb_blank(int blank_mode, struct fb_info *info);
503static void cirrusfb_fillrect(struct fb_info *info,
504 const struct fb_fillrect *region);
505static void cirrusfb_copyarea(struct fb_info *info,
506 const struct fb_copyarea *area);
507static void cirrusfb_imageblit(struct fb_info *info,
508 const struct fb_image *image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510/* function table of the above functions */
511static struct fb_ops cirrusfb_ops = {
512 .owner = THIS_MODULE,
513 .fb_open = cirrusfb_open,
514 .fb_release = cirrusfb_release,
515 .fb_setcolreg = cirrusfb_setcolreg,
516 .fb_check_var = cirrusfb_check_var,
517 .fb_set_par = cirrusfb_set_par,
518 .fb_pan_display = cirrusfb_pan_display,
519 .fb_blank = cirrusfb_blank,
520 .fb_fillrect = cirrusfb_fillrect,
521 .fb_copyarea = cirrusfb_copyarea,
522 .fb_imageblit = cirrusfb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523};
524
525/*--- Hardware Specific Routines -------------------------------------------*/
Krzysztof Helt8503df62007-10-16 01:29:08 -0700526static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 struct cirrusfb_regs *regs,
528 const struct fb_info *info);
529/*--- Internal routines ----------------------------------------------------*/
Krzysztof Helt9199ec52007-10-16 01:29:12 -0700530static void init_vgachip(struct fb_info *info);
Krzysztof Helt8503df62007-10-16 01:29:08 -0700531static void switch_monitor(struct cirrusfb_info *cinfo, int on);
532static void WGen(const struct cirrusfb_info *cinfo,
533 int regnum, unsigned char val);
534static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
535static void AttrOn(const struct cirrusfb_info *cinfo);
536static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
537static void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
538static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
539static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
540 unsigned char red, unsigned char green, unsigned char blue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541#if 0
Krzysztof Helt8503df62007-10-16 01:29:08 -0700542static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
543 unsigned char *red, unsigned char *green,
544 unsigned char *blue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545#endif
Krzysztof Helt8503df62007-10-16 01:29:08 -0700546static void cirrusfb_WaitBLT(u8 __iomem *regbase);
547static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
548 u_short curx, u_short cury,
549 u_short destx, u_short desty,
550 u_short width, u_short height,
551 u_short line_length);
552static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
553 u_short x, u_short y,
554 u_short width, u_short height,
555 u_char color, u_short line_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Krzysztof Helt8503df62007-10-16 01:29:08 -0700557static void bestclock(long freq, long *best,
558 long *nom, long *den,
559 long *div, long maxfreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561#ifdef CIRRUSFB_DEBUG
Krzysztof Helt8503df62007-10-16 01:29:08 -0700562static void cirrusfb_dump(void);
563static void cirrusfb_dbg_reg_dump(caddr_t regbase);
564static void cirrusfb_dbg_print_regs(caddr_t regbase,
Krzysztof Helt7345de32007-10-16 01:29:11 -0700565 enum cirrusfb_dbg_reg_class reg_class, ...);
Krzysztof Helt8503df62007-10-16 01:29:08 -0700566static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567#endif /* CIRRUSFB_DEBUG */
568
569/*** END PROTOTYPES ********************************************************/
570/*****************************************************************************/
571/*** BEGIN Interface Used by the World ***************************************/
572
Krzysztof Helt8503df62007-10-16 01:29:08 -0700573static int opencount;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
575/*--- Open /dev/fbx ---------------------------------------------------------*/
Krzysztof Helt8503df62007-10-16 01:29:08 -0700576static int cirrusfb_open(struct fb_info *info, int user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 if (opencount++ == 0)
Krzysztof Helt8503df62007-10-16 01:29:08 -0700579 switch_monitor(info->par, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return 0;
581}
582
583/*--- Close /dev/fbx --------------------------------------------------------*/
Krzysztof Helt8503df62007-10-16 01:29:08 -0700584static int cirrusfb_release(struct fb_info *info, int user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 if (--opencount == 0)
Krzysztof Helt8503df62007-10-16 01:29:08 -0700587 switch_monitor(info->par, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 return 0;
589}
590
591/**** END Interface used by the World *************************************/
592/****************************************************************************/
593/**** BEGIN Hardware specific Routines **************************************/
594
595/* Get a good MCLK value */
Krzysztof Helt8503df62007-10-16 01:29:08 -0700596static long cirrusfb_get_mclk(long freq, int bpp, long *div)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 long mclk;
599
Krzysztof Helt8503df62007-10-16 01:29:08 -0700600 assert(div != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
603 * Assume a 64-bit data path for now. The formula is:
604 * ((B * PCLK * 2)/W) * 1.2
605 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
606 mclk = ((bpp / 8) * freq * 2) / 4;
607 mclk = (mclk * 12) / 10;
608 if (mclk < 50000)
609 mclk = 50000;
Krzysztof Helt8503df62007-10-16 01:29:08 -0700610 DPRINTK("Use MCLK of %ld kHz\n", mclk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 /* Calculate value for SR1F. Multiply by 2 so we can round up. */
613 mclk = ((mclk * 16) / 14318);
614 mclk = (mclk + 1) / 2;
Krzysztof Helt8503df62007-10-16 01:29:08 -0700615 DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 /* Determine if we should use MCLK instead of VCLK, and if so, what we
618 * should divide it by to get VCLK */
619 switch (freq) {
620 case 24751 ... 25249:
621 *div = 2;
Krzysztof Helt8503df62007-10-16 01:29:08 -0700622 DPRINTK("Using VCLK = MCLK/2\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 break;
624 case 49501 ... 50499:
625 *div = 1;
Krzysztof Helt8503df62007-10-16 01:29:08 -0700626 DPRINTK("Using VCLK = MCLK\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 break;
628 default:
629 *div = 0;
630 break;
631 }
632
633 return mclk;
634}
635
636static int cirrusfb_check_var(struct fb_var_screeninfo *var,
637 struct fb_info *info)
638{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 int nom, den; /* translyting from pixels->bytes */
640 int yres, i;
641 static struct { int xres, yres; } modes[] =
642 { { 1600, 1280 },
643 { 1280, 1024 },
644 { 1024, 768 },
645 { 800, 600 },
646 { 640, 480 },
647 { -1, -1 } };
648
649 switch (var->bits_per_pixel) {
650 case 0 ... 1:
651 var->bits_per_pixel = 1;
652 nom = 4;
653 den = 8;
654 break; /* 8 pixel per byte, only 1/4th of mem usable */
655 case 2 ... 8:
656 var->bits_per_pixel = 8;
657 nom = 1;
658 den = 1;
659 break; /* 1 pixel == 1 byte */
660 case 9 ... 16:
661 var->bits_per_pixel = 16;
662 nom = 2;
663 den = 1;
664 break; /* 2 bytes per pixel */
665 case 17 ... 24:
666 var->bits_per_pixel = 24;
667 nom = 3;
668 den = 1;
669 break; /* 3 bytes per pixel */
670 case 25 ... 32:
671 var->bits_per_pixel = 32;
672 nom = 4;
673 den = 1;
674 break; /* 4 bytes per pixel */
675 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -0700676 printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
677 "color depth not supported.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 var->xres, var->yres, var->bits_per_pixel);
Krzysztof Helt8503df62007-10-16 01:29:08 -0700679 DPRINTK("EXIT - EINVAL error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 return -EINVAL;
681 }
682
Krzysztof Helt9199ec52007-10-16 01:29:12 -0700683 if (var->xres * nom / den * var->yres > info->screen_size) {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700684 printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
685 "resolution too high to fit into video memory!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 var->xres, var->yres, var->bits_per_pixel);
Krzysztof Helt8503df62007-10-16 01:29:08 -0700687 DPRINTK("EXIT - EINVAL error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return -EINVAL;
689 }
690
691 /* use highest possible virtual resolution */
692 if (var->xres_virtual == -1 &&
693 var->yres_virtual == -1) {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700694 printk(KERN_INFO
695 "cirrusfb: using maximum available virtual resolution\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 for (i = 0; modes[i].xres != -1; i++) {
Krzysztof Helt9199ec52007-10-16 01:29:12 -0700697 int size = modes[i].xres * nom / den * modes[i].yres;
698 if (size < info->screen_size / 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 break;
700 }
701 if (modes[i].xres == -1) {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700702 printk(KERN_ERR "cirrusfb: could not find a virtual "
703 "resolution that fits into video memory!!\n");
704 DPRINTK("EXIT - EINVAL error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return -EINVAL;
706 }
707 var->xres_virtual = modes[i].xres;
708 var->yres_virtual = modes[i].yres;
709
Krzysztof Helt8503df62007-10-16 01:29:08 -0700710 printk(KERN_INFO "cirrusfb: virtual resolution set to "
711 "maximum of %dx%d\n", var->xres_virtual,
712 var->yres_virtual);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 }
714
715 if (var->xres_virtual < var->xres)
716 var->xres_virtual = var->xres;
717 if (var->yres_virtual < var->yres)
718 var->yres_virtual = var->yres;
719
720 if (var->xoffset < 0)
721 var->xoffset = 0;
722 if (var->yoffset < 0)
723 var->yoffset = 0;
724
725 /* truncate xoffset and yoffset to maximum if too high */
726 if (var->xoffset > var->xres_virtual - var->xres)
727 var->xoffset = var->xres_virtual - var->xres - 1;
728 if (var->yoffset > var->yres_virtual - var->yres)
729 var->yoffset = var->yres_virtual - var->yres - 1;
730
731 switch (var->bits_per_pixel) {
732 case 1:
733 var->red.offset = 0;
734 var->red.length = 1;
735 var->green.offset = 0;
736 var->green.length = 1;
737 var->blue.offset = 0;
738 var->blue.length = 1;
739 break;
740
741 case 8:
742 var->red.offset = 0;
743 var->red.length = 6;
744 var->green.offset = 0;
745 var->green.length = 6;
746 var->blue.offset = 0;
747 var->blue.length = 6;
748 break;
749
750 case 16:
Krzysztof Helt8503df62007-10-16 01:29:08 -0700751 if (isPReP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 var->red.offset = 2;
753 var->green.offset = -3;
754 var->blue.offset = 8;
755 } else {
756 var->red.offset = 10;
757 var->green.offset = 5;
758 var->blue.offset = 0;
759 }
760 var->red.length = 5;
761 var->green.length = 5;
762 var->blue.length = 5;
763 break;
764
765 case 24:
Krzysztof Helt8503df62007-10-16 01:29:08 -0700766 if (isPReP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 var->red.offset = 8;
768 var->green.offset = 16;
769 var->blue.offset = 24;
770 } else {
771 var->red.offset = 16;
772 var->green.offset = 8;
773 var->blue.offset = 0;
774 }
775 var->red.length = 8;
776 var->green.length = 8;
777 var->blue.length = 8;
778 break;
779
780 case 32:
Krzysztof Helt8503df62007-10-16 01:29:08 -0700781 if (isPReP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 var->red.offset = 8;
783 var->green.offset = 16;
784 var->blue.offset = 24;
785 } else {
786 var->red.offset = 16;
787 var->green.offset = 8;
788 var->blue.offset = 0;
789 }
790 var->red.length = 8;
791 var->green.length = 8;
792 var->blue.length = 8;
793 break;
794
795 default:
796 DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
Richard Knutssonc930faa2007-05-08 00:38:29 -0700797 assert(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 /* should never occur */
799 break;
800 }
801
802 var->red.msb_right =
803 var->green.msb_right =
804 var->blue.msb_right =
805 var->transp.offset =
806 var->transp.length =
807 var->transp.msb_right = 0;
808
809 yres = var->yres;
810 if (var->vmode & FB_VMODE_DOUBLE)
811 yres *= 2;
812 else if (var->vmode & FB_VMODE_INTERLACED)
813 yres = (yres + 1) / 2;
814
815 if (yres >= 1280) {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700816 printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; "
817 "special treatment required! (TODO)\n");
818 DPRINTK("EXIT - EINVAL error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return -EINVAL;
820 }
821
822 return 0;
823}
824
Krzysztof Helt8503df62007-10-16 01:29:08 -0700825static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 struct cirrusfb_regs *regs,
827 const struct fb_info *info)
828{
829 long freq;
830 long maxclock;
831 int maxclockidx = 0;
832 struct cirrusfb_info *cinfo = info->par;
833 int xres, hfront, hsync, hback;
834 int yres, vfront, vsync, vback;
835
Krzysztof Helt8503df62007-10-16 01:29:08 -0700836 switch (var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 case 1:
838 regs->line_length = var->xres_virtual / 8;
839 regs->visual = FB_VISUAL_MONO10;
840 maxclockidx = 0;
841 break;
842
843 case 8:
844 regs->line_length = var->xres_virtual;
845 regs->visual = FB_VISUAL_PSEUDOCOLOR;
846 maxclockidx = 1;
847 break;
848
849 case 16:
850 regs->line_length = var->xres_virtual * 2;
851 regs->visual = FB_VISUAL_DIRECTCOLOR;
852 maxclockidx = 2;
853 break;
854
855 case 24:
856 regs->line_length = var->xres_virtual * 3;
857 regs->visual = FB_VISUAL_DIRECTCOLOR;
858 maxclockidx = 3;
859 break;
860
861 case 32:
862 regs->line_length = var->xres_virtual * 4;
863 regs->visual = FB_VISUAL_DIRECTCOLOR;
864 maxclockidx = 4;
865 break;
866
867 default:
868 DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
Richard Knutssonc930faa2007-05-08 00:38:29 -0700869 assert(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 /* should never occur */
871 break;
872 }
873
874 regs->type = FB_TYPE_PACKED_PIXELS;
875
876 /* convert from ps to kHz */
877 freq = 1000000000 / var->pixclock;
878
Krzysztof Helt8503df62007-10-16 01:29:08 -0700879 DPRINTK("desired pixclock: %ld kHz\n", freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
882 regs->multiplexing = 0;
883
884 /* If the frequency is greater than we can support, we might be able
885 * to use multiplexing for the video mode */
886 if (freq > maxclock) {
887 switch (cinfo->btype) {
888 case BT_ALPINE:
889 case BT_GD5480:
890 regs->multiplexing = 1;
891 break;
892
893 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -0700894 printk(KERN_ERR "cirrusfb: Frequency greater "
895 "than maxclock (%ld kHz)\n", maxclock);
896 DPRINTK("EXIT - return -EINVAL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return -EINVAL;
898 }
899 }
900#if 0
901 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
902 * the VCLK is double the pixel clock. */
903 switch (var->bits_per_pixel) {
904 case 16:
905 case 32:
906 if (regs->HorizRes <= 800)
Krzysztof Helt8503df62007-10-16 01:29:08 -0700907 /* Xbh has this type of clock for 32-bit */
908 freq /= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 break;
910 }
911#endif
912
Krzysztof Helt8503df62007-10-16 01:29:08 -0700913 bestclock(freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
914 maxclock);
915 regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel,
916 &regs->divMCLK);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918 xres = var->xres;
919 hfront = var->right_margin;
920 hsync = var->hsync_len;
921 hback = var->left_margin;
922
923 yres = var->yres;
924 vfront = var->lower_margin;
925 vsync = var->vsync_len;
926 vback = var->upper_margin;
927
928 if (var->vmode & FB_VMODE_DOUBLE) {
929 yres *= 2;
930 vfront *= 2;
931 vsync *= 2;
932 vback *= 2;
933 } else if (var->vmode & FB_VMODE_INTERLACED) {
934 yres = (yres + 1) / 2;
935 vfront = (vfront + 1) / 2;
936 vsync = (vsync + 1) / 2;
937 vback = (vback + 1) / 2;
938 }
939 regs->HorizRes = xres;
940 regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
941 regs->HorizDispEnd = xres / 8 - 1;
942 regs->HorizBlankStart = xres / 8;
Krzysztof Helt8503df62007-10-16 01:29:08 -0700943 /* does not count with "-5" */
944 regs->HorizBlankEnd = regs->HorizTotal + 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 regs->HorizSyncStart = (xres + hfront) / 8 + 1;
946 regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
947
948 regs->VertRes = yres;
949 regs->VertTotal = yres + vfront + vsync + vback - 2;
950 regs->VertDispEnd = yres - 1;
951 regs->VertBlankStart = yres;
952 regs->VertBlankEnd = regs->VertTotal;
953 regs->VertSyncStart = yres + vfront - 1;
954 regs->VertSyncEnd = yres + vfront + vsync - 1;
955
956 if (regs->VertRes >= 1024) {
957 regs->VertTotal /= 2;
958 regs->VertSyncStart /= 2;
959 regs->VertSyncEnd /= 2;
960 regs->VertDispEnd /= 2;
961 }
962 if (regs->multiplexing) {
963 regs->HorizTotal /= 2;
964 regs->HorizSyncStart /= 2;
965 regs->HorizSyncEnd /= 2;
966 regs->HorizDispEnd /= 2;
967 }
968
969 return 0;
970}
971
Krzysztof Helt8503df62007-10-16 01:29:08 -0700972static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val,
973 int div)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Krzysztof Helt8503df62007-10-16 01:29:08 -0700975 assert(cinfo != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 if (div == 2) {
978 /* VCLK = MCLK/2 */
Krzysztof Helt8503df62007-10-16 01:29:08 -0700979 unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
980 vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1);
981 vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 } else if (div == 1) {
983 /* VCLK = MCLK */
Krzysztof Helt8503df62007-10-16 01:29:08 -0700984 unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
985 vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1);
986 vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 } else {
Krzysztof Helt8503df62007-10-16 01:29:08 -0700988 vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 }
990}
991
992/*************************************************************************
993 cirrusfb_set_par_foo()
994
995 actually writes the values for a new video mode into the hardware,
996**************************************************************************/
Krzysztof Helt8503df62007-10-16 01:29:08 -0700997static int cirrusfb_set_par_foo(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
999 struct cirrusfb_info *cinfo = info->par;
1000 struct fb_var_screeninfo *var = &info->var;
1001 struct cirrusfb_regs regs;
1002 u8 __iomem *regbase = cinfo->regbase;
1003 unsigned char tmp;
1004 int offset = 0, err;
1005 const struct cirrusfb_board_info_rec *bi;
1006
Krzysztof Helt8503df62007-10-16 01:29:08 -07001007 DPRINTK("ENTER\n");
1008 DPRINTK("Requested mode: %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 var->xres, var->yres, var->bits_per_pixel);
Krzysztof Helt8503df62007-10-16 01:29:08 -07001010 DPRINTK("pixclock: %d\n", var->pixclock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
Krzysztof Helt9199ec52007-10-16 01:29:12 -07001012 init_vgachip(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 err = cirrusfb_decode_var(var, &regs, info);
Krzysztof Helt8503df62007-10-16 01:29:08 -07001015 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 /* should never happen */
1017 DPRINTK("mode change aborted. invalid var.\n");
1018 return -EINVAL;
1019 }
1020
1021 bi = &cirrusfb_board_info[cinfo->btype];
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001024 vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 /* if debugging is enabled, all parameters get output before writing */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001027 DPRINTK("CRT0: %ld\n", regs.HorizTotal);
1028 vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Krzysztof Helt8503df62007-10-16 01:29:08 -07001030 DPRINTK("CRT1: %ld\n", regs.HorizDispEnd);
1031 vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Krzysztof Helt8503df62007-10-16 01:29:08 -07001033 DPRINTK("CRT2: %ld\n", regs.HorizBlankStart);
1034 vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Krzysztof Helt8503df62007-10-16 01:29:08 -07001036 /* + 128: Compatible read */
1037 DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32);
1038 vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
1039 128 + (regs.HorizBlankEnd % 32));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Krzysztof Helt8503df62007-10-16 01:29:08 -07001041 DPRINTK("CRT4: %ld\n", regs.HorizSyncStart);
1042 vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 tmp = regs.HorizSyncEnd % 32;
1045 if (regs.HorizBlankEnd & 32)
1046 tmp += 128;
Krzysztof Helt8503df62007-10-16 01:29:08 -07001047 DPRINTK("CRT5: %d\n", tmp);
1048 vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Krzysztof Helt8503df62007-10-16 01:29:08 -07001050 DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff);
1051 vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 tmp = 16; /* LineCompare bit #9 */
1054 if (regs.VertTotal & 256)
1055 tmp |= 1;
1056 if (regs.VertDispEnd & 256)
1057 tmp |= 2;
1058 if (regs.VertSyncStart & 256)
1059 tmp |= 4;
1060 if (regs.VertBlankStart & 256)
1061 tmp |= 8;
1062 if (regs.VertTotal & 512)
1063 tmp |= 32;
1064 if (regs.VertDispEnd & 512)
1065 tmp |= 64;
1066 if (regs.VertSyncStart & 512)
1067 tmp |= 128;
Krzysztof Helt8503df62007-10-16 01:29:08 -07001068 DPRINTK("CRT7: %d\n", tmp);
1069 vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
1071 tmp = 0x40; /* LineCompare bit #8 */
1072 if (regs.VertBlankStart & 512)
1073 tmp |= 0x20;
1074 if (var->vmode & FB_VMODE_DOUBLE)
1075 tmp |= 0x80;
Krzysztof Helt8503df62007-10-16 01:29:08 -07001076 DPRINTK("CRT9: %d\n", tmp);
1077 vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Krzysztof Helt8503df62007-10-16 01:29:08 -07001079 DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff);
1080 vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Krzysztof Helt8503df62007-10-16 01:29:08 -07001082 DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
1083 vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Krzysztof Helt8503df62007-10-16 01:29:08 -07001085 DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff);
1086 vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
Krzysztof Helt8503df62007-10-16 01:29:08 -07001088 DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff);
1089 vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Krzysztof Helt8503df62007-10-16 01:29:08 -07001091 DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
1092 vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
Krzysztof Helt8503df62007-10-16 01:29:08 -07001094 DPRINTK("CRT18: 0xff\n");
1095 vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 tmp = 0;
1098 if (var->vmode & FB_VMODE_INTERLACED)
1099 tmp |= 1;
1100 if (regs.HorizBlankEnd & 64)
1101 tmp |= 16;
1102 if (regs.HorizBlankEnd & 128)
1103 tmp |= 32;
1104 if (regs.VertBlankEnd & 256)
1105 tmp |= 64;
1106 if (regs.VertBlankEnd & 512)
1107 tmp |= 128;
1108
Krzysztof Helt8503df62007-10-16 01:29:08 -07001109 DPRINTK("CRT1a: %d\n", tmp);
1110 vga_wcrt(regbase, CL_CRT1A, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 /* set VCLK0 */
1113 /* hardware RefClock: 14.31818 MHz */
1114 /* formula: VClk = (OSC * N) / (D * (1+P)) */
1115 /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1116
Krzysztof Helt8503df62007-10-16 01:29:08 -07001117 vga_wseq(regbase, CL_SEQRB, regs.nom);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 tmp = regs.den << 1;
1119 if (regs.div != 0)
1120 tmp |= 1;
1121
Krzysztof Helt8503df62007-10-16 01:29:08 -07001122 /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if ((cinfo->btype == BT_SD64) ||
1124 (cinfo->btype == BT_ALPINE) ||
1125 (cinfo->btype == BT_GD5480))
Krzysztof Helt8503df62007-10-16 01:29:08 -07001126 tmp |= 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Krzysztof Helt8503df62007-10-16 01:29:08 -07001128 DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
1129 vga_wseq(regbase, CL_SEQR1B, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 if (regs.VertRes >= 1024)
1132 /* 1280x1024 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001133 vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 else
1135 /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1136 * address wrap, no compat. */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001137 vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Krzysztof Helt8503df62007-10-16 01:29:08 -07001139/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);
1140 * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 /* don't know if it would hurt to also program this if no interlaced */
1143 /* mode is used, but I feel better this way.. :-) */
1144 if (var->vmode & FB_VMODE_INTERLACED)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001145 vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 else
Krzysztof Helt8503df62007-10-16 01:29:08 -07001147 vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Krzysztof Helt8503df62007-10-16 01:29:08 -07001149 vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 /* adjust horizontal/vertical sync type (low/high) */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001152 /* enable display memory & CRTC I/O address for color mode */
1153 tmp = 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1155 tmp |= 0x40;
1156 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1157 tmp |= 0x80;
Krzysztof Helt8503df62007-10-16 01:29:08 -07001158 WGen(cinfo, VGA_MIS_W, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Krzysztof Helt8503df62007-10-16 01:29:08 -07001160 /* Screen A Preset Row-Scan register */
1161 vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
1162 /* text cursor on and start line */
1163 vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
1164 /* text cursor end line */
1165 vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 /******************************************************
1168 *
1169 * 1 bpp
1170 *
1171 */
1172
1173 /* programming for different color depths */
1174 if (var->bits_per_pixel == 1) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001175 DPRINTK("cirrusfb: preparing for 1 bit deep display\n");
1176 vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 /* SR07 */
1179 switch (cinfo->btype) {
1180 case BT_SD64:
1181 case BT_PICCOLO:
1182 case BT_PICASSO:
1183 case BT_SPECTRUM:
1184 case BT_PICASSO4:
1185 case BT_ALPINE:
1186 case BT_GD5480:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001187 DPRINTK(" (for GD54xx)\n");
1188 vga_wseq(regbase, CL_SEQR7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 regs.multiplexing ?
1190 bi->sr07_1bpp_mux : bi->sr07_1bpp);
1191 break;
1192
1193 case BT_LAGUNA:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001194 DPRINTK(" (for GD546x)\n");
1195 vga_wseq(regbase, CL_SEQR7,
1196 vga_rseq(regbase, CL_SEQR7) & ~0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 break;
1198
1199 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001200 printk(KERN_WARNING "cirrusfb: unknown Board\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 break;
1202 }
1203
1204 /* Extended Sequencer Mode */
1205 switch (cinfo->btype) {
1206 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001207 /* setting the SEQRF on SD64 is not necessary
1208 * (only during init)
1209 */
1210 DPRINTK("(for SD64)\n");
1211 /* MCLK select */
1212 vga_wseq(regbase, CL_SEQR1F, 0x1a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 break;
1214
1215 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001216 DPRINTK("(for Piccolo)\n");
1217 /* ### ueberall 0x22? */
1218 /* ##vorher 1c MCLK select */
1219 vga_wseq(regbase, CL_SEQR1F, 0x22);
1220 /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1221 vga_wseq(regbase, CL_SEQRF, 0xb0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 break;
1223
1224 case BT_PICASSO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001225 DPRINTK("(for Picasso)\n");
1226 /* ##vorher 22 MCLK select */
1227 vga_wseq(regbase, CL_SEQR1F, 0x22);
1228 /* ## vorher d0 avoid FIFO underruns..? */
1229 vga_wseq(regbase, CL_SEQRF, 0xd0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 break;
1231
1232 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001233 DPRINTK("(for Spectrum)\n");
1234 /* ### ueberall 0x22? */
1235 /* ##vorher 1c MCLK select */
1236 vga_wseq(regbase, CL_SEQR1F, 0x22);
1237 /* evtl d0? avoid FIFO underruns..? */
1238 vga_wseq(regbase, CL_SEQRF, 0xb0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 break;
1240
1241 case BT_PICASSO4:
1242 case BT_ALPINE:
1243 case BT_GD5480:
1244 case BT_LAGUNA:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001245 DPRINTK(" (for GD54xx)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 /* do nothing */
1247 break;
1248
1249 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001250 printk(KERN_WARNING "cirrusfb: unknown Board\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 break;
1252 }
1253
Krzysztof Helt8503df62007-10-16 01:29:08 -07001254 /* pixel mask: pass-through for first plane */
1255 WGen(cinfo, VGA_PEL_MSK, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (regs.multiplexing)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001257 /* hidden dac reg: 1280x1024 */
1258 WHDR(cinfo, 0x4a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 else
Krzysztof Helt8503df62007-10-16 01:29:08 -07001260 /* hidden dac: nothing */
1261 WHDR(cinfo, 0);
1262 /* memory mode: odd/even, ext. memory */
1263 vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
1264 /* plane mask: only write to first plane */
1265 vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 offset = var->xres_virtual / 16;
1267 }
1268
1269 /******************************************************
1270 *
1271 * 8 bpp
1272 *
1273 */
1274
1275 else if (var->bits_per_pixel == 8) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001276 DPRINTK("cirrusfb: preparing for 8 bit deep display\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 switch (cinfo->btype) {
1278 case BT_SD64:
1279 case BT_PICCOLO:
1280 case BT_PICASSO:
1281 case BT_SPECTRUM:
1282 case BT_PICASSO4:
1283 case BT_ALPINE:
1284 case BT_GD5480:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001285 DPRINTK(" (for GD54xx)\n");
1286 vga_wseq(regbase, CL_SEQR7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 regs.multiplexing ?
1288 bi->sr07_8bpp_mux : bi->sr07_8bpp);
1289 break;
1290
1291 case BT_LAGUNA:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001292 DPRINTK(" (for GD546x)\n");
1293 vga_wseq(regbase, CL_SEQR7,
1294 vga_rseq(regbase, CL_SEQR7) | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 break;
1296
1297 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001298 printk(KERN_WARNING "cirrusfb: unknown Board\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 break;
1300 }
1301
1302 switch (cinfo->btype) {
1303 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001304 /* MCLK select */
1305 vga_wseq(regbase, CL_SEQR1F, 0x1d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 break;
1307
1308 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001309 /* ### vorher 1c MCLK select */
1310 vga_wseq(regbase, CL_SEQR1F, 0x22);
1311 /* Fast Page-Mode writes */
1312 vga_wseq(regbase, CL_SEQRF, 0xb0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 break;
1314
1315 case BT_PICASSO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001316 /* ### vorher 1c MCLK select */
1317 vga_wseq(regbase, CL_SEQR1F, 0x22);
1318 /* Fast Page-Mode writes */
1319 vga_wseq(regbase, CL_SEQRF, 0xb0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 break;
1321
1322 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001323 /* ### vorher 1c MCLK select */
1324 vga_wseq(regbase, CL_SEQR1F, 0x22);
1325 /* Fast Page-Mode writes */
1326 vga_wseq(regbase, CL_SEQRF, 0xb0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 break;
1328
1329 case BT_PICASSO4:
1330#ifdef CONFIG_ZORRO
Krzysztof Helt8503df62007-10-16 01:29:08 -07001331 /* ### INCOMPLETE!! */
1332 vga_wseq(regbase, CL_SEQRF, 0xb8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333#endif
Krzysztof Helt8503df62007-10-16 01:29:08 -07001334/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 break;
1336
1337 case BT_ALPINE:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001338 DPRINTK(" (for GD543x)\n");
1339 cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 /* We already set SRF and SR1F */
1341 break;
1342
1343 case BT_GD5480:
1344 case BT_LAGUNA:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001345 DPRINTK(" (for GD54xx)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* do nothing */
1347 break;
1348
1349 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001350 printk(KERN_WARNING "cirrusfb: unknown Board\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 break;
1352 }
1353
Krzysztof Helt8503df62007-10-16 01:29:08 -07001354 /* mode register: 256 color mode */
1355 vga_wgfx(regbase, VGA_GFX_MODE, 64);
1356 /* pixel mask: pass-through all planes */
1357 WGen(cinfo, VGA_PEL_MSK, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (regs.multiplexing)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001359 /* hidden dac reg: 1280x1024 */
1360 WHDR(cinfo, 0x4a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 else
Krzysztof Helt8503df62007-10-16 01:29:08 -07001362 /* hidden dac: nothing */
1363 WHDR(cinfo, 0);
1364 /* memory mode: chain4, ext. memory */
1365 vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
1366 /* plane mask: enable writing to all 4 planes */
1367 vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 offset = var->xres_virtual / 8;
1369 }
1370
1371 /******************************************************
1372 *
1373 * 16 bpp
1374 *
1375 */
1376
1377 else if (var->bits_per_pixel == 16) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001378 DPRINTK("cirrusfb: preparing for 16 bit deep display\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 switch (cinfo->btype) {
1380 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001381 /* Extended Sequencer Mode: 256c col. mode */
1382 vga_wseq(regbase, CL_SEQR7, 0xf7);
1383 /* MCLK select */
1384 vga_wseq(regbase, CL_SEQR1F, 0x1e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 break;
1386
1387 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001388 vga_wseq(regbase, CL_SEQR7, 0x87);
1389 /* Fast Page-Mode writes */
1390 vga_wseq(regbase, CL_SEQRF, 0xb0);
1391 /* MCLK select */
1392 vga_wseq(regbase, CL_SEQR1F, 0x22);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 break;
1394
1395 case BT_PICASSO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001396 vga_wseq(regbase, CL_SEQR7, 0x27);
1397 /* Fast Page-Mode writes */
1398 vga_wseq(regbase, CL_SEQRF, 0xb0);
1399 /* MCLK select */
1400 vga_wseq(regbase, CL_SEQR1F, 0x22);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 break;
1402
1403 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001404 vga_wseq(regbase, CL_SEQR7, 0x87);
1405 /* Fast Page-Mode writes */
1406 vga_wseq(regbase, CL_SEQRF, 0xb0);
1407 /* MCLK select */
1408 vga_wseq(regbase, CL_SEQR1F, 0x22);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 break;
1410
1411 case BT_PICASSO4:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001412 vga_wseq(regbase, CL_SEQR7, 0x27);
1413/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 break;
1415
1416 case BT_ALPINE:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001417 DPRINTK(" (for GD543x)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 if (regs.HorizRes >= 1024)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001419 vga_wseq(regbase, CL_SEQR7, 0xa7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 else
Krzysztof Helt8503df62007-10-16 01:29:08 -07001421 vga_wseq(regbase, CL_SEQR7, 0xa3);
1422 cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 break;
1424
1425 case BT_GD5480:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001426 DPRINTK(" (for GD5480)\n");
1427 vga_wseq(regbase, CL_SEQR7, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 /* We already set SRF and SR1F */
1429 break;
1430
1431 case BT_LAGUNA:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001432 DPRINTK(" (for GD546x)\n");
1433 vga_wseq(regbase, CL_SEQR7,
1434 vga_rseq(regbase, CL_SEQR7) & ~0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 break;
1436
1437 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001438 printk(KERN_WARNING "CIRRUSFB: unknown Board\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 break;
1440 }
1441
Krzysztof Helt8503df62007-10-16 01:29:08 -07001442 /* mode register: 256 color mode */
1443 vga_wgfx(regbase, VGA_GFX_MODE, 64);
1444 /* pixel mask: pass-through all planes */
1445 WGen(cinfo, VGA_PEL_MSK, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446#ifdef CONFIG_PCI
Krzysztof Helt8503df62007-10-16 01:29:08 -07001447 WHDR(cinfo, 0xc0); /* Copy Xbh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448#elif defined(CONFIG_ZORRO)
1449 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001450 WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451#endif
Krzysztof Helt8503df62007-10-16 01:29:08 -07001452 /* memory mode: chain4, ext. memory */
1453 vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
1454 /* plane mask: enable writing to all 4 planes */
1455 vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 offset = var->xres_virtual / 4;
1457 }
1458
1459 /******************************************************
1460 *
1461 * 32 bpp
1462 *
1463 */
1464
1465 else if (var->bits_per_pixel == 32) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001466 DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 switch (cinfo->btype) {
1468 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001469 /* Extended Sequencer Mode: 256c col. mode */
1470 vga_wseq(regbase, CL_SEQR7, 0xf9);
1471 /* MCLK select */
1472 vga_wseq(regbase, CL_SEQR1F, 0x1e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 break;
1474
1475 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001476 vga_wseq(regbase, CL_SEQR7, 0x85);
1477 /* Fast Page-Mode writes */
1478 vga_wseq(regbase, CL_SEQRF, 0xb0);
1479 /* MCLK select */
1480 vga_wseq(regbase, CL_SEQR1F, 0x22);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 break;
1482
1483 case BT_PICASSO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001484 vga_wseq(regbase, CL_SEQR7, 0x25);
1485 /* Fast Page-Mode writes */
1486 vga_wseq(regbase, CL_SEQRF, 0xb0);
1487 /* MCLK select */
1488 vga_wseq(regbase, CL_SEQR1F, 0x22);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 break;
1490
1491 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001492 vga_wseq(regbase, CL_SEQR7, 0x85);
1493 /* Fast Page-Mode writes */
1494 vga_wseq(regbase, CL_SEQRF, 0xb0);
1495 /* MCLK select */
1496 vga_wseq(regbase, CL_SEQR1F, 0x22);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 break;
1498
1499 case BT_PICASSO4:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001500 vga_wseq(regbase, CL_SEQR7, 0x25);
1501/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 break;
1503
1504 case BT_ALPINE:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001505 DPRINTK(" (for GD543x)\n");
1506 vga_wseq(regbase, CL_SEQR7, 0xa9);
1507 cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 break;
1509
1510 case BT_GD5480:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001511 DPRINTK(" (for GD5480)\n");
1512 vga_wseq(regbase, CL_SEQR7, 0x19);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 /* We already set SRF and SR1F */
1514 break;
1515
1516 case BT_LAGUNA:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001517 DPRINTK(" (for GD546x)\n");
1518 vga_wseq(regbase, CL_SEQR7,
1519 vga_rseq(regbase, CL_SEQR7) & ~0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 break;
1521
1522 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001523 printk(KERN_WARNING "cirrusfb: unknown Board\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 break;
1525 }
1526
Krzysztof Helt8503df62007-10-16 01:29:08 -07001527 /* mode register: 256 color mode */
1528 vga_wgfx(regbase, VGA_GFX_MODE, 64);
1529 /* pixel mask: pass-through all planes */
1530 WGen(cinfo, VGA_PEL_MSK, 0xff);
1531 /* hidden dac reg: 8-8-8 mode (24 or 32) */
1532 WHDR(cinfo, 0xc5);
1533 /* memory mode: chain4, ext. memory */
1534 vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
1535 /* plane mask: enable writing to all 4 planes */
1536 vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 offset = var->xres_virtual / 4;
1538 }
1539
1540 /******************************************************
1541 *
1542 * unknown/unsupported bpp
1543 *
1544 */
1545
Krzysztof Helt8503df62007-10-16 01:29:08 -07001546 else
1547 printk(KERN_ERR "cirrusfb: What's this?? "
1548 " requested color depth == %d.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 var->bits_per_pixel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Krzysztof Helt8503df62007-10-16 01:29:08 -07001551 vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 tmp = 0x22;
1553 if (offset & 0x100)
1554 tmp |= 0x10; /* offset overflow bit */
1555
Krzysztof Helt8503df62007-10-16 01:29:08 -07001556 /* screen start addr #16-18, fastpagemode cycles */
1557 vga_wcrt(regbase, CL_CRT1B, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559 if (cinfo->btype == BT_SD64 ||
1560 cinfo->btype == BT_PICASSO4 ||
1561 cinfo->btype == BT_ALPINE ||
1562 cinfo->btype == BT_GD5480)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001563 /* screen start address bit 19 */
1564 vga_wcrt(regbase, CL_CRT1D, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
Krzysztof Helt8503df62007-10-16 01:29:08 -07001566 /* text cursor location high */
1567 vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0);
1568 /* text cursor location low */
1569 vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0);
1570 /* underline row scanline = at very bottom */
1571 vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Krzysztof Helt8503df62007-10-16 01:29:08 -07001573 /* controller mode */
1574 vga_wattr(regbase, VGA_ATC_MODE, 1);
1575 /* overscan (border) color */
1576 vga_wattr(regbase, VGA_ATC_OVERSCAN, 0);
1577 /* color plane enable */
1578 vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15);
1579 /* pixel panning */
1580 vga_wattr(regbase, CL_AR33, 0);
1581 /* color select */
1582 vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
1584 /* [ EGS: SetOffset(); ] */
1585 /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001586 AttrOn(cinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Krzysztof Helt8503df62007-10-16 01:29:08 -07001588 /* set/reset register */
1589 vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0);
1590 /* set/reset enable */
1591 vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0);
1592 /* color compare */
1593 vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0);
1594 /* data rotate */
1595 vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0);
1596 /* read map select */
1597 vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0);
1598 /* miscellaneous register */
1599 vga_wgfx(regbase, VGA_GFX_MISC, 1);
1600 /* color don't care */
1601 vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15);
1602 /* bit mask */
1603 vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
Krzysztof Helt8503df62007-10-16 01:29:08 -07001605 /* graphics cursor attributes: nothing special */
1606 vga_wseq(regbase, CL_SEQR12, 0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 /* finally, turn on everything - turn off "FullBandwidth" bit */
1609 /* also, set "DotClock%2" bit where requested */
1610 tmp = 0x01;
1611
1612/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1613 if (var->vmode & FB_VMODE_CLOCK_HALVE)
1614 tmp |= 0x08;
1615*/
1616
Krzysztof Helt8503df62007-10-16 01:29:08 -07001617 vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
1618 DPRINTK("CL_SEQR1: %d\n", tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620 cinfo->currentmode = regs;
1621 info->fix.type = regs.type;
1622 info->fix.visual = regs.visual;
1623 info->fix.line_length = regs.line_length;
1624
1625 /* pan to requested offset */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001626 cirrusfb_pan_display(var, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
1628#ifdef CIRRUSFB_DEBUG
Krzysztof Helt8503df62007-10-16 01:29:08 -07001629 cirrusfb_dump();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630#endif
1631
Krzysztof Helt8503df62007-10-16 01:29:08 -07001632 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 return 0;
1634}
1635
1636/* for some reason incomprehensible to me, cirrusfb requires that you write
1637 * the registers twice for the settings to take..grr. -dte */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001638static int cirrusfb_set_par(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639{
Krzysztof Helt8503df62007-10-16 01:29:08 -07001640 cirrusfb_set_par_foo(info);
1641 return cirrusfb_set_par_foo(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642}
1643
Krzysztof Helt8503df62007-10-16 01:29:08 -07001644static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1645 unsigned blue, unsigned transp,
1646 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
1648 struct cirrusfb_info *cinfo = info->par;
1649
1650 if (regno > 255)
1651 return -EINVAL;
1652
1653 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
1654 u32 v;
1655 red >>= (16 - info->var.red.length);
1656 green >>= (16 - info->var.green.length);
1657 blue >>= (16 - info->var.blue.length);
1658
Krzysztof Helt8503df62007-10-16 01:29:08 -07001659 if (regno >= 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 return 1;
1661 v = (red << info->var.red.offset) |
1662 (green << info->var.green.offset) |
1663 (blue << info->var.blue.offset);
1664
1665 switch (info->var.bits_per_pixel) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001666 case 8:
1667 cinfo->pseudo_palette[regno] = v;
1668 break;
1669 case 16:
1670 cinfo->pseudo_palette[regno] = v;
1671 break;
1672 case 24:
1673 case 32:
1674 cinfo->pseudo_palette[regno] = v;
1675 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 }
1677 return 0;
1678 }
1679
Krzysztof Helt8503df62007-10-16 01:29:08 -07001680 if (info->var.bits_per_pixel == 8)
1681 WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 return 0;
1684
1685}
1686
1687/*************************************************************************
1688 cirrusfb_pan_display()
1689
1690 performs display panning - provided hardware permits this
1691**************************************************************************/
Krzysztof Helt8503df62007-10-16 01:29:08 -07001692static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
1693 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
1695 int xoffset = 0;
1696 int yoffset = 0;
1697 unsigned long base;
1698 unsigned char tmp = 0, tmp2 = 0, xpix;
1699 struct cirrusfb_info *cinfo = info->par;
1700
Krzysztof Helt8503df62007-10-16 01:29:08 -07001701 DPRINTK("ENTER\n");
1702 DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 /* no range checks for xoffset and yoffset, */
1705 /* as fb_pan_display has already done this */
1706 if (var->vmode & FB_VMODE_YWRAP)
1707 return -EINVAL;
1708
1709 info->var.xoffset = var->xoffset;
1710 info->var.yoffset = var->yoffset;
1711
1712 xoffset = var->xoffset * info->var.bits_per_pixel / 8;
1713 yoffset = var->yoffset;
1714
1715 base = yoffset * cinfo->currentmode.line_length + xoffset;
1716
1717 if (info->var.bits_per_pixel == 1) {
1718 /* base is already correct */
1719 xpix = (unsigned char) (var->xoffset % 8);
1720 } else {
1721 base /= 4;
1722 xpix = (unsigned char) ((xoffset % 4) * 2);
1723 }
1724
Krzysztof Helt8503df62007-10-16 01:29:08 -07001725 cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 /* lower 8 + 8 bits of screen start address */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001728 vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO,
1729 (unsigned char) (base & 0xff));
1730 vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI,
1731 (unsigned char) (base >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733 /* construct bits 16, 17 and 18 of screen start address */
1734 if (base & 0x10000)
1735 tmp |= 0x01;
1736 if (base & 0x20000)
1737 tmp |= 0x04;
1738 if (base & 0x40000)
1739 tmp |= 0x08;
1740
Krzysztof Helt8503df62007-10-16 01:29:08 -07001741 /* 0xf2 is %11110010, exclude tmp bits */
1742 tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp;
1743 vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
1745 /* construct bit 19 of screen start address */
1746 if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
1747 tmp2 = 0;
1748 if (base & 0x80000)
1749 tmp2 = 0x80;
Krzysztof Helt8503df62007-10-16 01:29:08 -07001750 vga_wcrt(cinfo->regbase, CL_CRT1D, tmp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752
Krzysztof Helt8503df62007-10-16 01:29:08 -07001753 /* write pixel panning value to AR33; this does not quite work in 8bpp
1754 *
1755 * ### Piccolo..? Will this work?
1756 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (info->var.bits_per_pixel == 1)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001758 vga_wattr(cinfo->regbase, CL_AR33, xpix);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Krzysztof Helt8503df62007-10-16 01:29:08 -07001760 cirrusfb_WaitBLT(cinfo->regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Krzysztof Helt8503df62007-10-16 01:29:08 -07001762 DPRINTK("EXIT\n");
1763 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764}
1765
Krzysztof Helt8503df62007-10-16 01:29:08 -07001766static int cirrusfb_blank(int blank_mode, struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767{
1768 /*
Krzysztof Helt8503df62007-10-16 01:29:08 -07001769 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1770 * then the caller blanks by setting the CLUT (Color Look Up Table)
1771 * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
1772 * failed due to e.g. a video mode which doesn't support it.
1773 * Implements VESA suspend and powerdown modes on hardware that
1774 * supports disabling hsync/vsync:
1775 * blank_mode == 2: suspend vsync
1776 * blank_mode == 3: suspend hsync
1777 * blank_mode == 4: powerdown
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 */
1779 unsigned char val;
1780 struct cirrusfb_info *cinfo = info->par;
1781 int current_mode = cinfo->blank_mode;
1782
Krzysztof Helt8503df62007-10-16 01:29:08 -07001783 DPRINTK("ENTER, blank mode = %d\n", blank_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 if (info->state != FBINFO_STATE_RUNNING ||
1786 current_mode == blank_mode) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001787 DPRINTK("EXIT, returning 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 return 0;
1789 }
1790
1791 /* Undo current */
1792 if (current_mode == FB_BLANK_NORMAL ||
1793 current_mode == FB_BLANK_UNBLANK) {
1794 /* unblank the screen */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001795 val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
1796 /* clear "FullBandwidth" bit */
1797 vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 /* and undo VESA suspend trickery */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001799 vga_wgfx(cinfo->regbase, CL_GRE, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 }
1801
1802 /* set new */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001803 if (blank_mode > FB_BLANK_NORMAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 /* blank the screen */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001805 val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
1806 /* set "FullBandwidth" bit */
1807 vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 }
1809
1810 switch (blank_mode) {
1811 case FB_BLANK_UNBLANK:
1812 case FB_BLANK_NORMAL:
1813 break;
1814 case FB_BLANK_VSYNC_SUSPEND:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001815 vga_wgfx(cinfo->regbase, CL_GRE, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 break;
1817 case FB_BLANK_HSYNC_SUSPEND:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001818 vga_wgfx(cinfo->regbase, CL_GRE, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 break;
1820 case FB_BLANK_POWERDOWN:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001821 vga_wgfx(cinfo->regbase, CL_GRE, 0x06);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 break;
1823 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001824 DPRINTK("EXIT, returning 1\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 return 1;
1826 }
1827
1828 cinfo->blank_mode = blank_mode;
Krzysztof Helt8503df62007-10-16 01:29:08 -07001829 DPRINTK("EXIT, returning 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
1831 /* Let fbcon do a soft blank for us */
1832 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1833}
1834/**** END Hardware specific Routines **************************************/
1835/****************************************************************************/
1836/**** BEGIN Internal Routines ***********************************************/
1837
Krzysztof Helt9199ec52007-10-16 01:29:12 -07001838static void init_vgachip(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839{
Krzysztof Helt9199ec52007-10-16 01:29:12 -07001840 struct cirrusfb_info *cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 const struct cirrusfb_board_info_rec *bi;
1842
Krzysztof Helt8503df62007-10-16 01:29:08 -07001843 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
Krzysztof Helt8503df62007-10-16 01:29:08 -07001845 assert(cinfo != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 bi = &cirrusfb_board_info[cinfo->btype];
1848
1849 /* reset board globally */
1850 switch (cinfo->btype) {
1851 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001852 WSFR(cinfo, 0x01);
1853 udelay(500);
1854 WSFR(cinfo, 0x51);
1855 udelay(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 break;
1857 case BT_PICASSO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001858 WSFR2(cinfo, 0xff);
1859 udelay(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 break;
1861 case BT_SD64:
1862 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001863 WSFR(cinfo, 0x1f);
1864 udelay(500);
1865 WSFR(cinfo, 0x4f);
1866 udelay(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 break;
1868 case BT_PICASSO4:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001869 /* disable flickerfixer */
1870 vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
1871 mdelay(100);
1872 /* from Klaus' NetBSD driver: */
1873 vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
1874 /* put blitter into 542x compat */
1875 vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
1876 /* mode */
1877 vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 break;
1879
1880 case BT_GD5480:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001881 /* from Klaus' NetBSD driver: */
1882 vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 break;
1884
1885 case BT_ALPINE:
1886 /* Nothing to do to reset the board. */
1887 break;
1888
1889 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001890 printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 break;
1892 }
1893
Krzysztof Helt9199ec52007-10-16 01:29:12 -07001894 /* make sure RAM size set by this point */
1895 assert(info->screen_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 /* the P4 is not fully initialized here; I rely on it having been */
1898 /* inited under AmigaOS already, which seems to work just fine */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001899 /* (Klaus advised to do it this way) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 if (cinfo->btype != BT_PICASSO4) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001902 WGen(cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */
1903 WGen(cinfo, CL_POS102, 0x01);
1904 WGen(cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906 if (cinfo->btype != BT_SD64)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001907 WGen(cinfo, CL_VSSM2, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Krzysztof Helt8503df62007-10-16 01:29:08 -07001909 /* reset sequencer logic */
1910 vga_wseq(cinfo->regbase, CL_SEQR0, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
Krzysztof Helt8503df62007-10-16 01:29:08 -07001912 /* FullBandwidth (video off) and 8/9 dot clock */
1913 vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
1914 /* polarity (-/-), disable access to display memory,
1915 * VGA_CRTC_START_HI base address: color
1916 */
1917 WGen(cinfo, VGA_MIS_W, 0xc1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
Krzysztof Helt8503df62007-10-16 01:29:08 -07001919 /* "magic cookie" - doesn't make any sense to me.. */
1920/* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */
1921 /* unlock all extension registers */
1922 vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923
Krzysztof Helt8503df62007-10-16 01:29:08 -07001924 /* reset blitter */
1925 vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
1927 switch (cinfo->btype) {
1928 case BT_GD5480:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001929 vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 break;
1931 case BT_ALPINE:
1932 break;
1933 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001934 vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 break;
1936 default:
Krzysztof Helt8503df62007-10-16 01:29:08 -07001937 vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
1938 vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 break;
1940 }
1941 }
Krzysztof Helt8503df62007-10-16 01:29:08 -07001942 /* plane mask: nothing */
1943 vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
1944 /* character map select: doesn't even matter in gx mode */
1945 vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
1946 /* memory mode: chain-4, no odd/even, ext. memory */
1947 vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949 /* controller-internal base address of video memory */
1950 if (bi->init_sr07)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001951 vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Krzysztof Helt8503df62007-10-16 01:29:08 -07001953 /* vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
1954 /* EEPROM control: shouldn't be necessary to write to this at all.. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Krzysztof Helt8503df62007-10-16 01:29:08 -07001956 /* graphics cursor X position (incomplete; position gives rem. 3 bits */
1957 vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
1958 /* graphics cursor Y position (..."... ) */
1959 vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
1960 /* graphics cursor attributes */
1961 vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
1962 /* graphics cursor pattern address */
1963 vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
1965 /* writing these on a P4 might give problems.. */
1966 if (cinfo->btype != BT_PICASSO4) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07001967 /* configuration readback and ext. color */
1968 vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
1969 /* signature generator */
1970 vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972
1973 /* MCLK select etc. */
1974 if (bi->init_sr1f)
Krzysztof Helt8503df62007-10-16 01:29:08 -07001975 vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
Krzysztof Helt8503df62007-10-16 01:29:08 -07001977 /* Screen A preset row scan: none */
1978 vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
1979 /* Text cursor start: disable text cursor */
1980 vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
1981 /* Text cursor end: - */
1982 vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
1983 /* Screen start address high: 0 */
1984 vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00);
1985 /* Screen start address low: 0 */
1986 vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00);
1987 /* text cursor location high: 0 */
1988 vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
1989 /* text cursor location low: 0 */
1990 vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
Krzysztof Helt8503df62007-10-16 01:29:08 -07001992 /* Underline Row scanline: - */
1993 vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
1994 /* mode control: timing enable, byte mode, no compat modes */
1995 vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3);
1996 /* Line Compare: not needed */
1997 vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 /* ### add 0x40 for text modes with > 30 MHz pixclock */
Krzysztof Helt8503df62007-10-16 01:29:08 -07001999 /* ext. display controls: ext.adr. wrap */
2000 vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
Krzysztof Helt8503df62007-10-16 01:29:08 -07002002 /* Set/Reset registes: - */
2003 vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
2004 /* Set/Reset enable: - */
2005 vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
2006 /* Color Compare: - */
2007 vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
2008 /* Data Rotate: - */
2009 vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
2010 /* Read Map Select: - */
2011 vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
2012 /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
2013 vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
2014 /* Miscellaneous: memory map base address, graphics mode */
2015 vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
2016 /* Color Don't care: involve all planes */
2017 vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
2018 /* Bit Mask: no mask at all */
2019 vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 if (cinfo->btype == BT_ALPINE)
Krzysztof Helt8503df62007-10-16 01:29:08 -07002021 /* (5434 can't have bit 3 set for bitblt) */
2022 vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 else
Krzysztof Helt8503df62007-10-16 01:29:08 -07002024 /* Graphics controller mode extensions: finer granularity,
2025 * 8byte data latches
2026 */
2027 vga_wgfx(cinfo->regbase, CL_GRB, 0x28);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Krzysztof Helt8503df62007-10-16 01:29:08 -07002029 vga_wgfx(cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */
2030 vga_wgfx(cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */
2031 vga_wgfx(cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */
2032 /* Background color byte 1: - */
2033 /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
2034 /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
Krzysztof Helt8503df62007-10-16 01:29:08 -07002036 /* Attribute Controller palette registers: "identity mapping" */
2037 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
2038 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
2039 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
2040 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
2041 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
2042 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
2043 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
2044 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
2045 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
2046 vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
2047 vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
2048 vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
2049 vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
2050 vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
2051 vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
2052 vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Krzysztof Helt8503df62007-10-16 01:29:08 -07002054 /* Attribute Controller mode: graphics mode */
2055 vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
2056 /* Overscan color reg.: reg. 0 */
2057 vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
2058 /* Color Plane enable: Enable all 4 planes */
2059 vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
2060/* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
2061 /* Color Select: - */
2062 vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Krzysztof Helt8503df62007-10-16 01:29:08 -07002064 WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
2066 if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
Krzysztof Helt8503df62007-10-16 01:29:08 -07002067 /* polarity (-/-), enable display mem,
2068 * VGA_CRTC_START_HI i/o base = color
2069 */
2070 WGen(cinfo, VGA_MIS_W, 0xc3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Krzysztof Helt8503df62007-10-16 01:29:08 -07002072 /* BLT Start/status: Blitter reset */
2073 vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
2074 /* - " - : "end-of-reset" */
2075 vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
2077 /* misc... */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002078 WHDR(cinfo, 0); /* Hidden DAC register: - */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Krzysztof Helt8503df62007-10-16 01:29:08 -07002080 printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n",
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002081 info->screen_size);
Krzysztof Helt8503df62007-10-16 01:29:08 -07002082 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 return;
2084}
2085
Krzysztof Helt8503df62007-10-16 01:29:08 -07002086static void switch_monitor(struct cirrusfb_info *cinfo, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087{
2088#ifdef CONFIG_ZORRO /* only works on Zorro boards */
2089 static int IsOn = 0; /* XXX not ok for multiple boards */
2090
Krzysztof Helt8503df62007-10-16 01:29:08 -07002091 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
2093 if (cinfo->btype == BT_PICASSO4)
2094 return; /* nothing to switch */
2095 if (cinfo->btype == BT_ALPINE)
2096 return; /* nothing to switch */
2097 if (cinfo->btype == BT_GD5480)
2098 return; /* nothing to switch */
2099 if (cinfo->btype == BT_PICASSO) {
2100 if ((on && !IsOn) || (!on && IsOn))
Krzysztof Helt8503df62007-10-16 01:29:08 -07002101 WSFR(cinfo, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Krzysztof Helt8503df62007-10-16 01:29:08 -07002103 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 return;
2105 }
2106 if (on) {
2107 switch (cinfo->btype) {
2108 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07002109 WSFR(cinfo, cinfo->SFR | 0x21);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 break;
2111 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07002112 WSFR(cinfo, cinfo->SFR | 0x28);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 break;
2114 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07002115 WSFR(cinfo, 0x6f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 break;
2117 default: /* do nothing */ break;
2118 }
2119 } else {
2120 switch (cinfo->btype) {
2121 case BT_SD64:
Krzysztof Helt8503df62007-10-16 01:29:08 -07002122 WSFR(cinfo, cinfo->SFR & 0xde);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 break;
2124 case BT_PICCOLO:
Krzysztof Helt8503df62007-10-16 01:29:08 -07002125 WSFR(cinfo, cinfo->SFR & 0xd7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 break;
2127 case BT_SPECTRUM:
Krzysztof Helt8503df62007-10-16 01:29:08 -07002128 WSFR(cinfo, 0x4f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 break;
2130 default: /* do nothing */ break;
2131 }
2132 }
2133
Krzysztof Helt8503df62007-10-16 01:29:08 -07002134 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135#endif /* CONFIG_ZORRO */
2136}
2137
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138/******************************************/
2139/* Linux 2.6-style accelerated functions */
2140/******************************************/
2141
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002142static void cirrusfb_prim_fillrect(struct fb_info *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 const struct fb_fillrect *region)
2144{
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002145 struct cirrusfb_info *cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 int m; /* bytes per pixel */
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002147 u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
Antonino A. Daplas49d5c7b2005-11-29 19:34:43 -08002148 cinfo->pseudo_palette[region->color] : region->color;
2149
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002150 if (info->var.bits_per_pixel == 1) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002151 cirrusfb_RectFill(cinfo->regbase,
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002152 info->var.bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 region->dx / 8, region->dy,
2154 region->width / 8, region->height,
Antonino A. Daplas49d5c7b2005-11-29 19:34:43 -08002155 color,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 cinfo->currentmode.line_length);
2157 } else {
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002158 m = (info->var.bits_per_pixel + 7) / 8;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002159 cirrusfb_RectFill(cinfo->regbase,
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002160 info->var.bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 region->dx * m, region->dy,
2162 region->width * m, region->height,
Antonino A. Daplas49d5c7b2005-11-29 19:34:43 -08002163 color,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 cinfo->currentmode.line_length);
2165 }
2166 return;
2167}
2168
Krzysztof Helt8503df62007-10-16 01:29:08 -07002169static void cirrusfb_fillrect(struct fb_info *info,
2170 const struct fb_fillrect *region)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 struct fb_fillrect modded;
2173 int vxres, vyres;
2174
2175 if (info->state != FBINFO_STATE_RUNNING)
2176 return;
2177 if (info->flags & FBINFO_HWACCEL_DISABLED) {
2178 cfb_fillrect(info, region);
2179 return;
2180 }
2181
2182 vxres = info->var.xres_virtual;
2183 vyres = info->var.yres_virtual;
2184
2185 memcpy(&modded, region, sizeof(struct fb_fillrect));
2186
Krzysztof Helt8503df62007-10-16 01:29:08 -07002187 if (!modded.width || !modded.height ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 modded.dx >= vxres || modded.dy >= vyres)
2189 return;
2190
Krzysztof Helt8503df62007-10-16 01:29:08 -07002191 if (modded.dx + modded.width > vxres)
2192 modded.width = vxres - modded.dx;
2193 if (modded.dy + modded.height > vyres)
2194 modded.height = vyres - modded.dy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002196 cirrusfb_prim_fillrect(info, &modded);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197}
2198
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002199static void cirrusfb_prim_copyarea(struct fb_info *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 const struct fb_copyarea *area)
2201{
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002202 struct cirrusfb_info *cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 int m; /* bytes per pixel */
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002204
2205 if (info->var.bits_per_pixel == 1) {
2206 cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 area->sx / 8, area->sy,
2208 area->dx / 8, area->dy,
2209 area->width / 8, area->height,
2210 cinfo->currentmode.line_length);
2211 } else {
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002212 m = (info->var.bits_per_pixel + 7) / 8;
2213 cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 area->sx * m, area->sy,
2215 area->dx * m, area->dy,
2216 area->width * m, area->height,
2217 cinfo->currentmode.line_length);
2218 }
2219 return;
2220}
2221
Krzysztof Helt8503df62007-10-16 01:29:08 -07002222static void cirrusfb_copyarea(struct fb_info *info,
2223 const struct fb_copyarea *area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 struct fb_copyarea modded;
2226 u32 vxres, vyres;
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 modded.sx = area->sx;
2229 modded.sy = area->sy;
2230 modded.dx = area->dx;
2231 modded.dy = area->dy;
2232 modded.width = area->width;
2233 modded.height = area->height;
2234
2235 if (info->state != FBINFO_STATE_RUNNING)
2236 return;
2237 if (info->flags & FBINFO_HWACCEL_DISABLED) {
2238 cfb_copyarea(info, area);
2239 return;
2240 }
2241
2242 vxres = info->var.xres_virtual;
2243 vyres = info->var.yres_virtual;
2244
Krzysztof Helt8503df62007-10-16 01:29:08 -07002245 if (!modded.width || !modded.height ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 modded.sx >= vxres || modded.sy >= vyres ||
2247 modded.dx >= vxres || modded.dy >= vyres)
2248 return;
2249
Krzysztof Helt8503df62007-10-16 01:29:08 -07002250 if (modded.sx + modded.width > vxres)
2251 modded.width = vxres - modded.sx;
2252 if (modded.dx + modded.width > vxres)
2253 modded.width = vxres - modded.dx;
2254 if (modded.sy + modded.height > vyres)
2255 modded.height = vyres - modded.sy;
2256 if (modded.dy + modded.height > vyres)
2257 modded.height = vyres - modded.dy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002259 cirrusfb_prim_copyarea(info, &modded);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260}
2261
Krzysztof Helt8503df62007-10-16 01:29:08 -07002262static void cirrusfb_imageblit(struct fb_info *info,
2263 const struct fb_image *image)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264{
2265 struct cirrusfb_info *cinfo = info->par;
2266
Krzysztof Helt8503df62007-10-16 01:29:08 -07002267 cirrusfb_WaitBLT(cinfo->regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 cfb_imageblit(info, image);
2269}
2270
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271#ifdef CONFIG_PPC_PREP
2272#define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2273#define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
Krzysztof Helt8503df62007-10-16 01:29:08 -07002274static void get_prep_addrs(unsigned long *display, unsigned long *registers)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275{
Krzysztof Helt8503df62007-10-16 01:29:08 -07002276 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
2278 *display = PREP_VIDEO_BASE;
2279 *registers = (unsigned long) PREP_IO_BASE;
2280
Krzysztof Helt8503df62007-10-16 01:29:08 -07002281 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282}
2283
2284#endif /* CONFIG_PPC_PREP */
2285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286#ifdef CONFIG_PCI
Krzysztof Helt8503df62007-10-16 01:29:08 -07002287static int release_io_ports;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2290 * based on the DRAM bandwidth bit and DRAM bank switching bit. This
2291 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2292 * seem to have. */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002293static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294{
2295 unsigned long mem;
2296 unsigned char SRF;
2297
Krzysztof Helt8503df62007-10-16 01:29:08 -07002298 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Krzysztof Helt8503df62007-10-16 01:29:08 -07002300 SRF = vga_rseq(regbase, CL_SEQRF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 switch ((SRF & 0x18)) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002302 case 0x08:
2303 mem = 512 * 1024;
2304 break;
2305 case 0x10:
2306 mem = 1024 * 1024;
2307 break;
2308 /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2309 * on the 5430.
2310 */
2311 case 0x18:
2312 mem = 2048 * 1024;
2313 break;
2314 default:
2315 printk(KERN_WARNING "CLgenfb: Unknown memory size!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 mem = 1024 * 1024;
2317 }
Krzysztof Helt8503df62007-10-16 01:29:08 -07002318 if (SRF & 0x80)
2319 /* If DRAM bank switching is enabled, there must be twice as much
2320 * memory installed. (4MB on the 5434)
2321 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 mem *= 2;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2325
Krzysztof Helt8503df62007-10-16 01:29:08 -07002326 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 return mem;
2328}
2329
Krzysztof Helt8503df62007-10-16 01:29:08 -07002330static void get_pci_addrs(const struct pci_dev *pdev,
2331 unsigned long *display, unsigned long *registers)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332{
Krzysztof Helt8503df62007-10-16 01:29:08 -07002333 assert(pdev != NULL);
2334 assert(display != NULL);
2335 assert(registers != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Krzysztof Helt8503df62007-10-16 01:29:08 -07002337 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339 *display = 0;
2340 *registers = 0;
2341
2342 /* This is a best-guess for now */
2343
2344 if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
2345 *display = pci_resource_start(pdev, 1);
2346 *registers = pci_resource_start(pdev, 0);
2347 } else {
2348 *display = pci_resource_start(pdev, 0);
2349 *registers = pci_resource_start(pdev, 1);
2350 }
2351
Krzysztof Helt8503df62007-10-16 01:29:08 -07002352 assert(*display != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Krzysztof Helt8503df62007-10-16 01:29:08 -07002354 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355}
2356
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002357static void cirrusfb_pci_unmap(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358{
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002359 struct cirrusfb_info *cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 struct pci_dev *pdev = cinfo->pdev;
2361
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002362 iounmap(info->screen_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363#if 0 /* if system didn't claim this region, we would... */
2364 release_mem_region(0xA0000, 65535);
2365#endif
2366 if (release_io_ports)
2367 release_region(0x3C0, 32);
2368 pci_release_regions(pdev);
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002369 framebuffer_release(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370}
2371#endif /* CONFIG_PCI */
2372
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373#ifdef CONFIG_ZORRO
Krzysztof Helt8503df62007-10-16 01:29:08 -07002374static void __devexit cirrusfb_zorro_unmap(struct cirrusfb_info *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375{
2376 zorro_release_device(cinfo->zdev);
2377
2378 if (cinfo->btype == BT_PICASSO4) {
2379 cinfo->regbase -= 0x600000;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002380 iounmap((void *)cinfo->regbase);
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002381 iounmap(info->screen_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 } else {
2383 if (zorro_resource_start(cinfo->zdev) > 0x01000000)
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002384 iounmap(info->screen_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386 framebuffer_release(cinfo->info);
2387}
2388#endif /* CONFIG_ZORRO */
2389
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002390static int cirrusfb_set_fbinfo(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391{
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002392 struct cirrusfb_info *cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 struct fb_var_screeninfo *var = &info->var;
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 info->pseudo_palette = cinfo->pseudo_palette;
2396 info->flags = FBINFO_DEFAULT
2397 | FBINFO_HWACCEL_XPAN
2398 | FBINFO_HWACCEL_YPAN
2399 | FBINFO_HWACCEL_FILLRECT
2400 | FBINFO_HWACCEL_COPYAREA;
2401 if (noaccel)
2402 info->flags |= FBINFO_HWACCEL_DISABLED;
2403 info->fbops = &cirrusfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 if (cinfo->btype == BT_GD5480) {
2405 if (var->bits_per_pixel == 16)
2406 info->screen_base += 1 * MB_;
2407 if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
2408 info->screen_base += 2 * MB_;
2409 }
2410
2411 /* Fill fix common fields */
2412 strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
2413 sizeof(info->fix.id));
2414
2415 /* monochrome: only 1 memory plane */
2416 /* 8 bit and above: Use whole memory area */
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002417 info->fix.smem_len = info->screen_size;
2418 if (var->bits_per_pixel == 1)
2419 info->fix.smem_len /= 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 info->fix.type = cinfo->currentmode.type;
2421 info->fix.type_aux = 0;
2422 info->fix.visual = cinfo->currentmode.visual;
2423 info->fix.xpanstep = 1;
2424 info->fix.ypanstep = 1;
2425 info->fix.ywrapstep = 0;
2426 info->fix.line_length = cinfo->currentmode.line_length;
2427
2428 /* FIXME: map region at 0xB8000 if available, fill in here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 info->fix.mmio_len = 0;
2430 info->fix.accel = FB_ACCEL_NONE;
2431
2432 fb_alloc_cmap(&info->cmap, 256, 0);
2433
2434 return 0;
2435}
2436
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002437static int cirrusfb_register(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438{
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002439 struct cirrusfb_info *cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 int err;
Krzysztof Helt7345de32007-10-16 01:29:11 -07002441 enum cirrus_board btype;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
Krzysztof Helt8503df62007-10-16 01:29:08 -07002443 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
Krzysztof Helt8503df62007-10-16 01:29:08 -07002445 printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based "
2446 "graphic boards, v" CIRRUSFB_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 btype = cinfo->btype;
2449
2450 /* sanity checks */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002451 assert(btype != BT_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002453 DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
2455 /* Make pretend we've set the var so our structures are in a "good" */
2456 /* state, even though we haven't written the mode to the hw yet... */
2457 info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
2458 info->var.activate = FB_ACTIVATE_NOW;
2459
2460 err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
2461 if (err < 0) {
2462 /* should never happen */
2463 DPRINTK("choking on default var... umm, no good.\n");
2464 goto err_unmap_cirrusfb;
2465 }
2466
2467 /* set all the vital stuff */
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002468 cirrusfb_set_fbinfo(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
2470 err = register_framebuffer(info);
2471 if (err < 0) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002472 printk(KERN_ERR "cirrusfb: could not register "
2473 "fb device; err = %d!\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 goto err_dealloc_cmap;
2475 }
2476
Krzysztof Helt8503df62007-10-16 01:29:08 -07002477 DPRINTK("EXIT, returning 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 return 0;
2479
2480err_dealloc_cmap:
2481 fb_dealloc_cmap(&info->cmap);
2482err_unmap_cirrusfb:
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002483 cinfo->unmap(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 return err;
2485}
2486
Krzysztof Helt8503df62007-10-16 01:29:08 -07002487static void __devexit cirrusfb_cleanup(struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488{
2489 struct cirrusfb_info *cinfo = info->par;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002490 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
Krzysztof Helt8503df62007-10-16 01:29:08 -07002492 switch_monitor(cinfo, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Krzysztof Helt8503df62007-10-16 01:29:08 -07002494 unregister_framebuffer(info);
2495 fb_dealloc_cmap(&info->cmap);
2496 printk("Framebuffer unregistered\n");
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002497 cinfo->unmap(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Krzysztof Helt8503df62007-10-16 01:29:08 -07002499 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500}
2501
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502#ifdef CONFIG_PCI
Krzysztof Helt8503df62007-10-16 01:29:08 -07002503static int cirrusfb_pci_register(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 const struct pci_device_id *ent)
2505{
2506 struct cirrusfb_info *cinfo;
2507 struct fb_info *info;
Krzysztof Helt7345de32007-10-16 01:29:11 -07002508 enum cirrus_board btype;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 unsigned long board_addr, board_size;
2510 int ret;
2511
2512 ret = pci_enable_device(pdev);
2513 if (ret < 0) {
2514 printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
2515 goto err_out;
2516 }
2517
2518 info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
2519 if (!info) {
2520 printk(KERN_ERR "cirrusfb: could not allocate memory\n");
2521 ret = -ENOMEM;
2522 goto err_disable;
2523 }
2524
2525 cinfo = info->par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 cinfo->pdev = pdev;
Krzysztof Helt7345de32007-10-16 01:29:11 -07002527 cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
Krzysztof Helt7345de32007-10-16 01:29:11 -07002529 DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 pdev->resource[0].start, btype);
Krzysztof Helt7345de32007-10-16 01:29:11 -07002531 DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
Krzysztof Helt8503df62007-10-16 01:29:08 -07002533 if (isPReP) {
2534 pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535#ifdef CONFIG_PPC_PREP
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002536 get_prep_addrs(&board_addr, &info->fix.mmio_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537#endif
Krzysztof Helt8503df62007-10-16 01:29:08 -07002538 /* PReP dies if we ioremap the IO registers, but it works w/out... */
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002539 cinfo->regbase = (char __iomem *) info->fix.mmio_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 } else {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002541 DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n");
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002542 get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
Krzysztof Helt8503df62007-10-16 01:29:08 -07002543 /* FIXME: this forces VGA. alternatives? */
2544 cinfo->regbase = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
2546
Krzysztof Helt8503df62007-10-16 01:29:08 -07002547 DPRINTK("Board address: 0x%lx, register address: 0x%lx\n",
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002548 board_addr, info->fix.mmio_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
2550 board_size = (btype == BT_GD5480) ?
Krzysztof Helt8503df62007-10-16 01:29:08 -07002551 32 * MB_ : cirrusfb_get_memsize(cinfo->regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
2553 ret = pci_request_regions(pdev, "cirrusfb");
Krzysztof Helt8503df62007-10-16 01:29:08 -07002554 if (ret < 0) {
2555 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
2556 "abort\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 board_addr);
2558 goto err_release_fb;
2559 }
2560#if 0 /* if the system didn't claim this region, we would... */
2561 if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
2562 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
2563,
2564 0xA0000L);
2565 ret = -EBUSY;
2566 goto err_release_regions;
2567 }
2568#endif
2569 if (request_region(0x3C0, 32, "cirrusfb"))
2570 release_io_ports = 1;
2571
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002572 info->screen_base = ioremap(board_addr, board_size);
2573 if (!info->screen_base) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 ret = -EIO;
2575 goto err_release_legacy;
2576 }
2577
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002578 info->fix.smem_start = board_addr;
2579 info->screen_size = board_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 cinfo->unmap = cirrusfb_pci_unmap;
2581
Krzysztof Helt8503df62007-10-16 01:29:08 -07002582 printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ",
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002583 info->screen_size / KB_, board_addr);
Krzysztof Helt8503df62007-10-16 01:29:08 -07002584 printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 pci_set_drvdata(pdev, info);
2586
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002587 ret = cirrusfb_register(info);
Amol Ladd8b8c0a2006-12-08 02:40:13 -08002588 if (ret)
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002589 iounmap(info->screen_base);
Amol Ladd8b8c0a2006-12-08 02:40:13 -08002590 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
2592err_release_legacy:
2593 if (release_io_ports)
2594 release_region(0x3C0, 32);
2595#if 0
2596 release_mem_region(0xA0000, 65535);
2597err_release_regions:
2598#endif
2599 pci_release_regions(pdev);
2600err_release_fb:
2601 framebuffer_release(info);
2602err_disable:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603err_out:
2604 return ret;
2605}
2606
Krzysztof Helt8503df62007-10-16 01:29:08 -07002607static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
2609 struct fb_info *info = pci_get_drvdata(pdev);
Krzysztof Helt8503df62007-10-16 01:29:08 -07002610 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
Krzysztof Helt8503df62007-10-16 01:29:08 -07002612 cirrusfb_cleanup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
Krzysztof Helt8503df62007-10-16 01:29:08 -07002614 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615}
2616
2617static struct pci_driver cirrusfb_pci_driver = {
2618 .name = "cirrusfb",
2619 .id_table = cirrusfb_pci_table,
2620 .probe = cirrusfb_pci_register,
2621 .remove = __devexit_p(cirrusfb_pci_unregister),
2622#ifdef CONFIG_PM
2623#if 0
2624 .suspend = cirrusfb_pci_suspend,
2625 .resume = cirrusfb_pci_resume,
2626#endif
2627#endif
2628};
2629#endif /* CONFIG_PCI */
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631#ifdef CONFIG_ZORRO
2632static int cirrusfb_zorro_register(struct zorro_dev *z,
2633 const struct zorro_device_id *ent)
2634{
2635 struct cirrusfb_info *cinfo;
2636 struct fb_info *info;
Krzysztof Helt7345de32007-10-16 01:29:11 -07002637 enum cirrus_board btype;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 struct zorro_dev *z2 = NULL;
2639 unsigned long board_addr, board_size, size;
2640 int ret;
2641
2642 btype = ent->driver_data;
2643 if (cirrusfb_zorro_table2[btype].id2)
2644 z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
2645 size = cirrusfb_zorro_table2[btype].size;
2646 printk(KERN_INFO "cirrusfb: %s board detected; ",
2647 cirrusfb_board_info[btype].name);
2648
2649 info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
2650 if (!info) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002651 printk(KERN_ERR "cirrusfb: could not allocate memory\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 ret = -ENOMEM;
2653 goto err_out;
2654 }
2655
2656 cinfo = info->par;
2657 cinfo->info = info;
2658 cinfo->btype = btype;
2659
Krzysztof Helt8503df62007-10-16 01:29:08 -07002660 assert(z > 0);
2661 assert(z2 >= 0);
2662 assert(btype != BT_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
2664 cinfo->zdev = z;
2665 board_addr = zorro_resource_start(z);
2666 board_size = zorro_resource_len(z);
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002667 info->screen_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
2669 if (!zorro_request_device(z, "cirrusfb")) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002670 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
2671 "abort\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 board_addr);
2673 ret = -EBUSY;
2674 goto err_release_fb;
2675 }
2676
Krzysztof Helt8503df62007-10-16 01:29:08 -07002677 printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
2679 ret = -EIO;
2680
2681 if (btype == BT_PICASSO4) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002682 printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684 /* To be precise, for the P4 this is not the */
2685 /* begin of the board, but the begin of RAM. */
2686 /* for P4, map in its address space in 2 chunks (### TEST! ) */
2687 /* (note the ugly hardcoded 16M number) */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002688 cinfo->regbase = ioremap(board_addr, 16777216);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 if (!cinfo->regbase)
2690 goto err_release_region;
2691
Krzysztof Helt8503df62007-10-16 01:29:08 -07002692 DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
2693 cinfo->regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 cinfo->regbase += 0x600000;
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002695 info->fix.mmio_start = board_addr + 0x600000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002697 info->fix.smem_start = board_addr + 16777216;
2698 info->screen_base = ioremap(info->fix.smem_start, 16777216);
2699 if (!info->screen_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 goto err_unmap_regbase;
2701 } else {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002702 printk(KERN_INFO " REG at $%lx\n",
2703 (unsigned long) z2->resource.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002705 info->fix.smem_start = board_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 if (board_addr > 0x01000000)
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002707 info->screen_base = ioremap(board_addr, board_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 else
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002709 info->screen_base = (caddr_t) ZTWO_VADDR(board_addr);
2710 if (!info->screen_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 goto err_release_region;
2712
2713 /* set address for REG area of board */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002714 cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002715 info->fix.mmio_start = z2->resource.start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Krzysztof Helt8503df62007-10-16 01:29:08 -07002717 DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
2718 cinfo->regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
2720 cinfo->unmap = cirrusfb_zorro_unmap;
2721
Krzysztof Helt8503df62007-10-16 01:29:08 -07002722 printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 zorro_set_drvdata(z, info);
2724
Amol Ladd8b8c0a2006-12-08 02:40:13 -08002725 ret = cirrusfb_register(cinfo);
2726 if (ret) {
2727 if (btype == BT_PICASSO4) {
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002728 iounmap(info->screen_base);
Amol Ladd8b8c0a2006-12-08 02:40:13 -08002729 iounmap(cinfo->regbase - 0x600000);
2730 } else if (board_addr > 0x01000000)
Krzysztof Helt9199ec52007-10-16 01:29:12 -07002731 iounmap(info->screen_base);
Amol Ladd8b8c0a2006-12-08 02:40:13 -08002732 }
2733 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
2735err_unmap_regbase:
2736 /* Parental advisory: explicit hack */
2737 iounmap(cinfo->regbase - 0x600000);
2738err_release_region:
2739 release_region(board_addr, board_size);
2740err_release_fb:
2741 framebuffer_release(info);
2742err_out:
2743 return ret;
2744}
2745
2746void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
2747{
2748 struct fb_info *info = zorro_get_drvdata(z);
Krzysztof Helt8503df62007-10-16 01:29:08 -07002749 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Krzysztof Helt8503df62007-10-16 01:29:08 -07002751 cirrusfb_cleanup(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752
Krzysztof Helt8503df62007-10-16 01:29:08 -07002753 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754}
2755
2756static struct zorro_driver cirrusfb_zorro_driver = {
2757 .name = "cirrusfb",
2758 .id_table = cirrusfb_zorro_table,
2759 .probe = cirrusfb_zorro_register,
2760 .remove = __devexit_p(cirrusfb_zorro_unregister),
2761};
2762#endif /* CONFIG_ZORRO */
2763
2764static int __init cirrusfb_init(void)
2765{
2766 int error = 0;
2767
2768#ifndef MODULE
2769 char *option = NULL;
2770
2771 if (fb_get_options("cirrusfb", &option))
2772 return -ENODEV;
2773 cirrusfb_setup(option);
2774#endif
2775
2776#ifdef CONFIG_ZORRO
Bjorn Helgaas33d86752006-03-25 03:07:20 -08002777 error |= zorro_register_driver(&cirrusfb_zorro_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778#endif
2779#ifdef CONFIG_PCI
2780 error |= pci_register_driver(&cirrusfb_pci_driver);
2781#endif
2782 return error;
2783}
2784
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785#ifndef MODULE
2786static int __init cirrusfb_setup(char *options) {
2787 char *this_opt, s[32];
2788 int i;
2789
Krzysztof Helt8503df62007-10-16 01:29:08 -07002790 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791
2792 if (!options || !*options)
2793 return 0;
2794
Krzysztof Helt8503df62007-10-16 01:29:08 -07002795 while ((this_opt = strsep(&options, ",")) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 if (!*this_opt) continue;
2797
2798 DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
2799
2800 for (i = 0; i < NUM_TOTAL_MODES; i++) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002801 sprintf(s, "mode:%s", cirrusfb_predefined[i].name);
2802 if (strcmp(this_opt, s) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 cirrusfb_def_mode = i;
2804 }
2805 if (!strcmp(this_opt, "noaccel"))
2806 noaccel = 1;
2807 }
2808 return 0;
2809}
2810#endif
2811
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 /*
2813 * Modularization
2814 */
2815
2816MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2817MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2818MODULE_LICENSE("GPL");
2819
Krzysztof Helt8503df62007-10-16 01:29:08 -07002820static void __exit cirrusfb_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821{
2822#ifdef CONFIG_PCI
2823 pci_unregister_driver(&cirrusfb_pci_driver);
2824#endif
2825#ifdef CONFIG_ZORRO
2826 zorro_unregister_driver(&cirrusfb_zorro_driver);
2827#endif
2828}
2829
2830module_init(cirrusfb_init);
2831
2832#ifdef MODULE
2833module_exit(cirrusfb_exit);
2834#endif
2835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836/**********************************************************************/
2837/* about the following functions - I have used the same names for the */
2838/* functions as Markus Wild did in his Retina driver for NetBSD as */
2839/* they just made sense for this purpose. Apart from that, I wrote */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002840/* these functions myself. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841/**********************************************************************/
2842
2843/*** WGen() - write into one of the external/general registers ***/
Krzysztof Helt8503df62007-10-16 01:29:08 -07002844static void WGen(const struct cirrusfb_info *cinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 int regnum, unsigned char val)
2846{
2847 unsigned long regofs = 0;
2848
2849 if (cinfo->btype == BT_PICASSO) {
2850 /* Picasso II specific hack */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002851/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
2852 regnum == CL_VSSM2) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2854 regofs = 0xfff;
2855 }
2856
Krzysztof Helt8503df62007-10-16 01:29:08 -07002857 vga_w(cinfo->regbase, regofs + regnum, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858}
2859
2860/*** RGen() - read out one of the external/general registers ***/
Krzysztof Helt8503df62007-10-16 01:29:08 -07002861static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
2863 unsigned long regofs = 0;
2864
2865 if (cinfo->btype == BT_PICASSO) {
2866 /* Picasso II specific hack */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002867/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
2868 regnum == CL_VSSM2) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2870 regofs = 0xfff;
2871 }
2872
Krzysztof Helt8503df62007-10-16 01:29:08 -07002873 return vga_r(cinfo->regbase, regofs + regnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874}
2875
2876/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
Krzysztof Helt8503df62007-10-16 01:29:08 -07002877static void AttrOn(const struct cirrusfb_info *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878{
Krzysztof Helt8503df62007-10-16 01:29:08 -07002879 assert(cinfo != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
Krzysztof Helt8503df62007-10-16 01:29:08 -07002881 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
Krzysztof Helt8503df62007-10-16 01:29:08 -07002883 if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 /* if we're just in "write value" mode, write back the */
2885 /* same value as before to not modify anything */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002886 vga_w(cinfo->regbase, VGA_ATT_IW,
2887 vga_r(cinfo->regbase, VGA_ATT_R));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 }
2889 /* turn on video bit */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002890/* vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
2891 vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892
2893 /* dummy write on Reg0 to be on "write index" mode next time */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002894 vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
Krzysztof Helt8503df62007-10-16 01:29:08 -07002896 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897}
2898
2899/*** WHDR() - write into the Hidden DAC register ***/
2900/* as the HDR is the only extension register that requires special treatment
2901 * (the other extension registers are accessible just like the "ordinary"
2902 * registers of their functional group) here is a specialized routine for
2903 * accessing the HDR
2904 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002905static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906{
2907 unsigned char dummy;
2908
2909 if (cinfo->btype == BT_PICASSO) {
2910 /* Klaus' hint for correct access to HDR on some boards */
2911 /* first write 0 to pixel mask (3c6) */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002912 WGen(cinfo, VGA_PEL_MSK, 0x00);
2913 udelay(200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 /* next read dummy from pixel address (3c8) */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002915 dummy = RGen(cinfo, VGA_PEL_IW);
2916 udelay(200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 }
2918 /* now do the usual stuff to access the HDR */
2919
Krzysztof Helt8503df62007-10-16 01:29:08 -07002920 dummy = RGen(cinfo, VGA_PEL_MSK);
2921 udelay(200);
2922 dummy = RGen(cinfo, VGA_PEL_MSK);
2923 udelay(200);
2924 dummy = RGen(cinfo, VGA_PEL_MSK);
2925 udelay(200);
2926 dummy = RGen(cinfo, VGA_PEL_MSK);
2927 udelay(200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
Krzysztof Helt8503df62007-10-16 01:29:08 -07002929 WGen(cinfo, VGA_PEL_MSK, val);
2930 udelay(200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931
2932 if (cinfo->btype == BT_PICASSO) {
2933 /* now first reset HDR access counter */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002934 dummy = RGen(cinfo, VGA_PEL_IW);
2935 udelay(200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
2937 /* and at the end, restore the mask value */
2938 /* ## is this mask always 0xff? */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002939 WGen(cinfo, VGA_PEL_MSK, 0xff);
2940 udelay(200);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 }
2942}
2943
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944/*** WSFR() - write to the "special function register" (SFR) ***/
Krzysztof Helt8503df62007-10-16 01:29:08 -07002945static void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946{
2947#ifdef CONFIG_ZORRO
Krzysztof Helt8503df62007-10-16 01:29:08 -07002948 assert(cinfo->regbase != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 cinfo->SFR = val;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002950 z_writeb(val, cinfo->regbase + 0x8000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951#endif
2952}
2953
2954/* The Picasso has a second register for switching the monitor bit */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002955static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956{
2957#ifdef CONFIG_ZORRO
2958 /* writing an arbitrary value to this one causes the monitor switcher */
2959 /* to flip to Amiga display */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002960 assert(cinfo->regbase != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 cinfo->SFR = val;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002962 z_writeb(val, cinfo->regbase + 0x9000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963#endif
2964}
2965
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966/*** WClut - set CLUT entry (range: 0..63) ***/
Krzysztof Helt8503df62007-10-16 01:29:08 -07002967static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 unsigned char green, unsigned char blue)
2969{
2970 unsigned int data = VGA_PEL_D;
2971
2972 /* address write mode register is not translated.. */
Krzysztof Helt8503df62007-10-16 01:29:08 -07002973 vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974
2975 if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2976 cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
2977 /* but DAC data register IS, at least for Picasso II */
2978 if (cinfo->btype == BT_PICASSO)
2979 data += 0xfff;
Krzysztof Helt8503df62007-10-16 01:29:08 -07002980 vga_w(cinfo->regbase, data, red);
2981 vga_w(cinfo->regbase, data, green);
2982 vga_w(cinfo->regbase, data, blue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 } else {
Krzysztof Helt8503df62007-10-16 01:29:08 -07002984 vga_w(cinfo->regbase, data, blue);
2985 vga_w(cinfo->regbase, data, green);
2986 vga_w(cinfo->regbase, data, red);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 }
2988}
2989
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990#if 0
2991/*** RClut - read CLUT entry (range 0..63) ***/
Krzysztof Helt8503df62007-10-16 01:29:08 -07002992static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 unsigned char *green, unsigned char *blue)
2994{
2995 unsigned int data = VGA_PEL_D;
2996
Krzysztof Helt8503df62007-10-16 01:29:08 -07002997 vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998
2999 if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
3000 cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
3001 if (cinfo->btype == BT_PICASSO)
3002 data += 0xfff;
Krzysztof Helt8503df62007-10-16 01:29:08 -07003003 *red = vga_r(cinfo->regbase, data);
3004 *green = vga_r(cinfo->regbase, data);
3005 *blue = vga_r(cinfo->regbase, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 } else {
Krzysztof Helt8503df62007-10-16 01:29:08 -07003007 *blue = vga_r(cinfo->regbase, data);
3008 *green = vga_r(cinfo->regbase, data);
3009 *red = vga_r(cinfo->regbase, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 }
3011}
3012#endif
3013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014/*******************************************************************
3015 cirrusfb_WaitBLT()
3016
3017 Wait for the BitBLT engine to complete a possible earlier job
3018*********************************************************************/
3019
3020/* FIXME: use interrupts instead */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003021static void cirrusfb_WaitBLT(u8 __iomem *regbase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022{
3023 /* now busy-wait until we're done */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003024 while (vga_rgfx(regbase, CL_GR31) & 0x08)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 /* do nothing */ ;
3026}
3027
3028/*******************************************************************
3029 cirrusfb_BitBLT()
3030
3031 perform accelerated "scrolling"
3032********************************************************************/
3033
Krzysztof Helt8503df62007-10-16 01:29:08 -07003034static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
3035 u_short curx, u_short cury,
3036 u_short destx, u_short desty,
3037 u_short width, u_short height,
3038 u_short line_length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039{
3040 u_short nwidth, nheight;
3041 u_long nsrc, ndest;
3042 u_char bltmode;
3043
Krzysztof Helt8503df62007-10-16 01:29:08 -07003044 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
3046 nwidth = width - 1;
3047 nheight = height - 1;
3048
3049 bltmode = 0x00;
3050 /* if source adr < dest addr, do the Blt backwards */
3051 if (cury <= desty) {
3052 if (cury == desty) {
3053 /* if src and dest are on the same line, check x */
3054 if (curx < destx)
3055 bltmode |= 0x01;
3056 } else
3057 bltmode |= 0x01;
3058 }
3059 if (!bltmode) {
3060 /* standard case: forward blitting */
3061 nsrc = (cury * line_length) + curx;
3062 ndest = (desty * line_length) + destx;
3063 } else {
Krzysztof Helt8503df62007-10-16 01:29:08 -07003064 /* this means start addresses are at the end,
3065 * counting backwards
3066 */
3067 nsrc = cury * line_length + curx +
3068 nheight * line_length + nwidth;
3069 ndest = desty * line_length + destx +
3070 nheight * line_length + nwidth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 }
3072
3073 /*
3074 run-down of registers to be programmed:
3075 destination pitch
3076 source pitch
3077 BLT width/height
3078 source start
3079 destination start
3080 BLT mode
3081 BLT ROP
3082 VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
3083 start/stop
3084 */
3085
Krzysztof Helt8503df62007-10-16 01:29:08 -07003086 cirrusfb_WaitBLT(regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
3088 /* pitch: set to line_length */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003089 /* dest pitch low */
3090 vga_wgfx(regbase, CL_GR24, line_length & 0xff);
3091 /* dest pitch hi */
3092 vga_wgfx(regbase, CL_GR25, line_length >> 8);
3093 /* source pitch low */
3094 vga_wgfx(regbase, CL_GR26, line_length & 0xff);
3095 /* source pitch hi */
3096 vga_wgfx(regbase, CL_GR27, line_length >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
3098 /* BLT width: actual number of pixels - 1 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003099 /* BLT width low */
3100 vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
3101 /* BLT width hi */
3102 vga_wgfx(regbase, CL_GR21, nwidth >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103
3104 /* BLT height: actual number of lines -1 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003105 /* BLT height low */
3106 vga_wgfx(regbase, CL_GR22, nheight & 0xff);
3107 /* BLT width hi */
3108 vga_wgfx(regbase, CL_GR23, nheight >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 /* BLT destination */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003111 /* BLT dest low */
3112 vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
3113 /* BLT dest mid */
3114 vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
3115 /* BLT dest hi */
3116 vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
3118 /* BLT source */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003119 /* BLT src low */
3120 vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
3121 /* BLT src mid */
3122 vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
3123 /* BLT src hi */
3124 vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
3126 /* BLT mode */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003127 vga_wgfx(regbase, CL_GR30, bltmode); /* BLT mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
3129 /* BLT ROP: SrcCopy */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003130 vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
3132 /* and finally: GO! */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003133 vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
Krzysztof Helt8503df62007-10-16 01:29:08 -07003135 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136}
3137
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138/*******************************************************************
3139 cirrusfb_RectFill()
3140
3141 perform accelerated rectangle fill
3142********************************************************************/
3143
Krzysztof Helt8503df62007-10-16 01:29:08 -07003144static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 u_short x, u_short y, u_short width, u_short height,
3146 u_char color, u_short line_length)
3147{
3148 u_short nwidth, nheight;
3149 u_long ndest;
3150 u_char op;
3151
Krzysztof Helt8503df62007-10-16 01:29:08 -07003152 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
3154 nwidth = width - 1;
3155 nheight = height - 1;
3156
3157 ndest = (y * line_length) + x;
3158
Krzysztof Helt8503df62007-10-16 01:29:08 -07003159 cirrusfb_WaitBLT(regbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 /* pitch: set to line_length */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003162 vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
3163 vga_wgfx(regbase, CL_GR25, line_length >> 8); /* dest pitch hi */
3164 vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */
3165 vga_wgfx(regbase, CL_GR27, line_length >> 8); /* source pitch hi */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
3167 /* BLT width: actual number of pixels - 1 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003168 vga_wgfx(regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
3169 vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT width hi */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
3171 /* BLT height: actual number of lines -1 */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003172 vga_wgfx(regbase, CL_GR22, nheight & 0xff); /* BLT height low */
3173 vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT width hi */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
3175 /* BLT destination */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003176 /* BLT dest low */
3177 vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
3178 /* BLT dest mid */
3179 vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
3180 /* BLT dest hi */
3181 vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
3183 /* BLT source: set to 0 (is a dummy here anyway) */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003184 vga_wgfx(regbase, CL_GR2C, 0x00); /* BLT src low */
3185 vga_wgfx(regbase, CL_GR2D, 0x00); /* BLT src mid */
3186 vga_wgfx(regbase, CL_GR2E, 0x00); /* BLT src hi */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187
3188 /* This is a ColorExpand Blt, using the */
3189 /* same color for foreground and background */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003190 vga_wgfx(regbase, VGA_GFX_SR_VALUE, color); /* foreground color */
3191 vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color); /* background color */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193 op = 0xc0;
3194 if (bits_per_pixel == 16) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07003195 vga_wgfx(regbase, CL_GR10, color); /* foreground color */
3196 vga_wgfx(regbase, CL_GR11, color); /* background color */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 op = 0x50;
3198 op = 0xd0;
3199 } else if (bits_per_pixel == 32) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07003200 vga_wgfx(regbase, CL_GR10, color); /* foreground color */
3201 vga_wgfx(regbase, CL_GR11, color); /* background color */
3202 vga_wgfx(regbase, CL_GR12, color); /* foreground color */
3203 vga_wgfx(regbase, CL_GR13, color); /* background color */
3204 vga_wgfx(regbase, CL_GR14, 0); /* foreground color */
3205 vga_wgfx(regbase, CL_GR15, 0); /* background color */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 op = 0x50;
3207 op = 0xf0;
3208 }
3209 /* BLT mode: color expand, Enable 8x8 copy (faster?) */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003210 vga_wgfx(regbase, CL_GR30, op); /* BLT mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
3212 /* BLT ROP: SrcCopy */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003213 vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
3215 /* and finally: GO! */
Krzysztof Helt8503df62007-10-16 01:29:08 -07003216 vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Krzysztof Helt8503df62007-10-16 01:29:08 -07003218 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219}
3220
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221/**************************************************************************
3222 * bestclock() - determine closest possible clock lower(?) than the
3223 * desired pixel clock
3224 **************************************************************************/
Krzysztof Helt8503df62007-10-16 01:29:08 -07003225static void bestclock(long freq, long *best, long *nom,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 long *den, long *div, long maxfreq)
3227{
3228 long n, h, d, f;
3229
Krzysztof Helt8503df62007-10-16 01:29:08 -07003230 assert(best != NULL);
3231 assert(nom != NULL);
3232 assert(den != NULL);
3233 assert(div != NULL);
3234 assert(maxfreq > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235
3236 *nom = 0;
3237 *den = 0;
3238 *div = 0;
3239
Krzysztof Helt8503df62007-10-16 01:29:08 -07003240 DPRINTK("ENTER\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
3242 if (freq < 8000)
3243 freq = 8000;
3244
3245 if (freq > maxfreq)
3246 freq = maxfreq;
3247
3248 *best = 0;
3249 f = freq * 10;
3250
3251 for (n = 32; n < 128; n++) {
3252 d = (143181 * n) / f;
3253 if ((d >= 7) && (d <= 63)) {
3254 if (d > 31)
3255 d = (d / 2) * 2;
3256 h = (14318 * n) / d;
Krzysztof Helt8503df62007-10-16 01:29:08 -07003257 if (abs(h - freq) < abs(*best - freq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 *best = h;
3259 *nom = n;
3260 if (d < 32) {
3261 *den = d;
3262 *div = 0;
3263 } else {
3264 *den = d / 2;
3265 *div = 1;
3266 }
3267 }
3268 }
3269 d = ((143181 * n) + f - 1) / f;
3270 if ((d >= 7) && (d <= 63)) {
3271 if (d > 31)
3272 d = (d / 2) * 2;
3273 h = (14318 * n) / d;
Krzysztof Helt8503df62007-10-16 01:29:08 -07003274 if (abs(h - freq) < abs(*best - freq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 *best = h;
3276 *nom = n;
3277 if (d < 32) {
3278 *den = d;
3279 *div = 0;
3280 } else {
3281 *den = d / 2;
3282 *div = 1;
3283 }
3284 }
3285 }
3286 }
3287
Krzysztof Helt8503df62007-10-16 01:29:08 -07003288 DPRINTK("Best possible values for given frequency:\n");
3289 DPRINTK(" best: %ld kHz nom: %ld den: %ld div: %ld\n",
3290 freq, *nom, *den, *div);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291
Krzysztof Helt8503df62007-10-16 01:29:08 -07003292 DPRINTK("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293}
3294
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295/* -------------------------------------------------------------------------
3296 *
3297 * debugging functions
3298 *
3299 * -------------------------------------------------------------------------
3300 */
3301
3302#ifdef CIRRUSFB_DEBUG
3303
3304/**
3305 * cirrusfb_dbg_print_byte
3306 * @name: name associated with byte value to be displayed
3307 * @val: byte value to be displayed
3308 *
3309 * DESCRIPTION:
3310 * Display an indented string, along with a hexidecimal byte value, and
3311 * its decoded bits. Bits 7 through 0 are listed in left-to-right
3312 * order.
3313 */
3314
3315static
Krzysztof Helt8503df62007-10-16 01:29:08 -07003316void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317{
Krzysztof Helt8503df62007-10-16 01:29:08 -07003318 DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3319 name, val,
3320 val & 0x80 ? '1' : '0',
3321 val & 0x40 ? '1' : '0',
3322 val & 0x20 ? '1' : '0',
3323 val & 0x10 ? '1' : '0',
3324 val & 0x08 ? '1' : '0',
3325 val & 0x04 ? '1' : '0',
3326 val & 0x02 ? '1' : '0',
3327 val & 0x01 ? '1' : '0');
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328}
3329
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330/**
3331 * cirrusfb_dbg_print_regs
3332 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3333 * @reg_class: type of registers to read: %CRT, or %SEQ
3334 *
3335 * DESCRIPTION:
3336 * Dumps the given list of VGA CRTC registers. If @base is %NULL,
3337 * old-style I/O ports are queried for information, otherwise MMIO is
3338 * used at the given @base address to query the information.
3339 */
3340
3341static
Krzysztof Helt8503df62007-10-16 01:29:08 -07003342void cirrusfb_dbg_print_regs(caddr_t regbase,
Krzysztof Helt7345de32007-10-16 01:29:11 -07003343 enum cirrusfb_dbg_reg_class reg_class, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344{
3345 va_list list;
3346 unsigned char val = 0;
3347 unsigned reg;
3348 char *name;
3349
Krzysztof Helt8503df62007-10-16 01:29:08 -07003350 va_start(list, reg_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
Krzysztof Helt8503df62007-10-16 01:29:08 -07003352 name = va_arg(list, char *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 while (name != NULL) {
Krzysztof Helt8503df62007-10-16 01:29:08 -07003354 reg = va_arg(list, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355
3356 switch (reg_class) {
3357 case CRT:
Krzysztof Helt8503df62007-10-16 01:29:08 -07003358 val = vga_rcrt(regbase, (unsigned char) reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 break;
3360 case SEQ:
Krzysztof Helt8503df62007-10-16 01:29:08 -07003361 val = vga_rseq(regbase, (unsigned char) reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 break;
3363 default:
3364 /* should never occur */
Richard Knutssonc930faa2007-05-08 00:38:29 -07003365 assert(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 break;
3367 }
3368
Krzysztof Helt8503df62007-10-16 01:29:08 -07003369 cirrusfb_dbg_print_byte(name, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Krzysztof Helt8503df62007-10-16 01:29:08 -07003371 name = va_arg(list, char *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 }
3373
Krzysztof Helt8503df62007-10-16 01:29:08 -07003374 va_end(list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375}
3376
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377/**
3378 * cirrusfb_dump
3379 * @cirrusfbinfo:
3380 *
3381 * DESCRIPTION:
3382 */
3383
Krzysztof Helt8503df62007-10-16 01:29:08 -07003384static void cirrusfb_dump(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385{
Krzysztof Helt8503df62007-10-16 01:29:08 -07003386 cirrusfb_dbg_reg_dump(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387}
3388
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389/**
3390 * cirrusfb_dbg_reg_dump
3391 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3392 *
3393 * DESCRIPTION:
3394 * Dumps a list of interesting VGA and CIRRUSFB registers. If @base is %NULL,
3395 * old-style I/O ports are queried for information, otherwise MMIO is
3396 * used at the given @base address to query the information.
3397 */
3398
3399static
Krzysztof Helt8503df62007-10-16 01:29:08 -07003400void cirrusfb_dbg_reg_dump(caddr_t regbase)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401{
Krzysztof Helt8503df62007-10-16 01:29:08 -07003402 DPRINTK("CIRRUSFB VGA CRTC register dump:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403
Krzysztof Helt8503df62007-10-16 01:29:08 -07003404 cirrusfb_dbg_print_regs(regbase, CRT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 "CR00", 0x00,
3406 "CR01", 0x01,
3407 "CR02", 0x02,
3408 "CR03", 0x03,
3409 "CR04", 0x04,
3410 "CR05", 0x05,
3411 "CR06", 0x06,
3412 "CR07", 0x07,
3413 "CR08", 0x08,
3414 "CR09", 0x09,
3415 "CR0A", 0x0A,
3416 "CR0B", 0x0B,
3417 "CR0C", 0x0C,
3418 "CR0D", 0x0D,
3419 "CR0E", 0x0E,
3420 "CR0F", 0x0F,
3421 "CR10", 0x10,
3422 "CR11", 0x11,
3423 "CR12", 0x12,
3424 "CR13", 0x13,
3425 "CR14", 0x14,
3426 "CR15", 0x15,
3427 "CR16", 0x16,
3428 "CR17", 0x17,
3429 "CR18", 0x18,
3430 "CR22", 0x22,
3431 "CR24", 0x24,
3432 "CR26", 0x26,
3433 "CR2D", 0x2D,
3434 "CR2E", 0x2E,
3435 "CR2F", 0x2F,
3436 "CR30", 0x30,
3437 "CR31", 0x31,
3438 "CR32", 0x32,
3439 "CR33", 0x33,
3440 "CR34", 0x34,
3441 "CR35", 0x35,
3442 "CR36", 0x36,
3443 "CR37", 0x37,
3444 "CR38", 0x38,
3445 "CR39", 0x39,
3446 "CR3A", 0x3A,
3447 "CR3B", 0x3B,
3448 "CR3C", 0x3C,
3449 "CR3D", 0x3D,
3450 "CR3E", 0x3E,
3451 "CR3F", 0x3F,
3452 NULL);
3453
Krzysztof Helt8503df62007-10-16 01:29:08 -07003454 DPRINTK("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455
Krzysztof Helt8503df62007-10-16 01:29:08 -07003456 DPRINTK("CIRRUSFB VGA SEQ register dump:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457
Krzysztof Helt8503df62007-10-16 01:29:08 -07003458 cirrusfb_dbg_print_regs(regbase, SEQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 "SR00", 0x00,
3460 "SR01", 0x01,
3461 "SR02", 0x02,
3462 "SR03", 0x03,
3463 "SR04", 0x04,
3464 "SR08", 0x08,
3465 "SR09", 0x09,
3466 "SR0A", 0x0A,
3467 "SR0B", 0x0B,
3468 "SR0D", 0x0D,
3469 "SR10", 0x10,
3470 "SR11", 0x11,
3471 "SR12", 0x12,
3472 "SR13", 0x13,
3473 "SR14", 0x14,
3474 "SR15", 0x15,
3475 "SR16", 0x16,
3476 "SR17", 0x17,
3477 "SR18", 0x18,
3478 "SR19", 0x19,
3479 "SR1A", 0x1A,
3480 "SR1B", 0x1B,
3481 "SR1C", 0x1C,
3482 "SR1D", 0x1D,
3483 "SR1E", 0x1E,
3484 "SR1F", 0x1F,
3485 NULL);
3486
Krzysztof Helt8503df62007-10-16 01:29:08 -07003487 DPRINTK("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488}
3489
3490#endif /* CIRRUSFB_DEBUG */
3491