OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [video/] [tdfxfb.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *
3
 * tdfxfb.c
4
 *
5
 * Author: Hannu Mallat <hmallat@cc.hut.fi>
6
 *
7
 * Copyright © 1999 Hannu Mallat
8
 * All rights reserved
9
 *
10
 * Created      : Thu Sep 23 18:17:43 1999, hmallat
11
 * Last modified: Tue Nov  2 21:19:47 1999, hmallat
12
 *
13
 * Lots of the information here comes from the Daryll Strauss' Banshee
14
 * patches to the XF86 server, and the rest comes from the 3dfx
15
 * Banshee specification. I'm very much indebted to Daryll for his
16
 * work on the X server.
17
 *
18
 * Voodoo3 support was contributed Harold Oga. Lots of additions
19
 * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
20
 * Kesmarki. Thanks guys!
21
 *
22
 * Voodoo1 and Voodoo2 support aren't relevant to this driver as they
23
 * behave very differently from the Voodoo3/4/5. For anyone wanting to
24
 * use frame buffer on the Voodoo1/2, see the sstfb driver (which is
25
 * located at http://www.sourceforge.net/projects/sstfb).
26
 *
27
 * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
28
 * I do wish the next version is a bit more complete. Without the XF86
29
 * patches I couldn't have gotten even this far... for instance, the
30
 * extensions to the VGA register set go completely unmentioned in the
31
 * spec! Also, lots of references are made to the 'SST core', but no
32
 * spec is publicly available, AFAIK.
33
 *
34
 * The structure of this driver comes pretty much from the Permedia
35
 * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
36
 *
37
 * TODO:
38
 * - support for 16/32 bpp needs fixing (funky bootup penguin)
39
 * - multihead support (basically need to support an array of fb_infos)
40
 * - support other architectures (PPC, Alpha); does the fact that the VGA
41
 *   core can be accessed only thru I/O (not memory mapped) complicate
42
 *   things?
43
 *
44
 * Version history:
45
 *
46
 * 0.1.3 (released 1999-11-02) added Attila's panning support, code
47
 *                             reorg, hwcursor address page size alignment
48
 *                             (for mmaping both frame buffer and regs),
49
 *                             and my changes to get rid of hardcoded
50
 *                             VGA i/o register locations (uses PCI
51
 *                             configuration info now)
52
 * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
53
 *                             improvements
54
 * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
55
 * 0.1.0 (released 1999-10-06) initial version
56
 *
57
 */
58
 
59
#include <linux/config.h>
60
#include <linux/module.h>
61
#include <linux/kernel.h>
62
#include <linux/errno.h>
63
#include <linux/string.h>
64
#include <linux/mm.h>
65
#include <linux/tty.h>
66
#include <linux/slab.h>
67
#include <linux/vmalloc.h>
68
#include <linux/delay.h>
69
#include <linux/interrupt.h>
70
#include <linux/fb.h>
71
#include <linux/selection.h>
72
#include <linux/console.h>
73
#include <linux/init.h>
74
#include <linux/pci.h>
75
#include <linux/nvram.h>
76
#include <linux/kd.h>
77
#include <linux/vt_kern.h>
78
#include <asm/io.h>
79
#include <linux/timer.h>
80
 
81
#ifdef CONFIG_MTRR
82
#include <asm/mtrr.h>
83
#endif
84
 
85
#include <video/fbcon.h>
86
#include <video/fbcon-cfb8.h>
87
#include <video/fbcon-cfb16.h>
88
#include <video/fbcon-cfb24.h>
89
#include <video/fbcon-cfb32.h>
90
 
91
#include <linux/spinlock.h>
92
 
93
#ifndef PCI_DEVICE_ID_3DFX_VOODOO5
94
#define PCI_DEVICE_ID_3DFX_VOODOO5      0x0009
95
#endif
96
 
97
/* membase0 register offsets */
98
#define STATUS          0x00
99
#define PCIINIT0        0x04
100
#define SIPMONITOR      0x08
101
#define LFBMEMORYCONFIG 0x0c
102
#define MISCINIT0       0x10
103
#define MISCINIT1       0x14
104
#define DRAMINIT0       0x18
105
#define DRAMINIT1       0x1c
106
#define AGPINIT         0x20
107
#define TMUGBEINIT      0x24
108
#define VGAINIT0        0x28
109
#define VGAINIT1        0x2c
110
#define DRAMCOMMAND     0x30
111
#define DRAMDATA        0x34
112
/* reserved             0x38 */
113
/* reserved             0x3c */
114
#define PLLCTRL0        0x40
115
#define PLLCTRL1        0x44
116
#define PLLCTRL2        0x48
117
#define DACMODE         0x4c
118
#define DACADDR         0x50
119
#define DACDATA         0x54
120
#define RGBMAXDELTA     0x58
121
#define VIDPROCCFG      0x5c
122
#define HWCURPATADDR    0x60
123
#define HWCURLOC        0x64
124
#define HWCURC0         0x68
125
#define HWCURC1         0x6c
126
#define VIDINFORMAT     0x70
127
#define VIDINSTATUS     0x74
128
#define VIDSERPARPORT   0x78
129
#define VIDINXDELTA     0x7c
130
#define VIDININITERR    0x80
131
#define VIDINYDELTA     0x84
132
#define VIDPIXBUFTHOLD  0x88
133
#define VIDCHRMIN       0x8c
134
#define VIDCHRMAX       0x90
135
#define VIDCURLIN       0x94
136
#define VIDSCREENSIZE   0x98
137
#define VIDOVRSTARTCRD  0x9c
138
#define VIDOVRENDCRD    0xa0
139
#define VIDOVRDUDX      0xa4
140
#define VIDOVRDUDXOFF   0xa8
141
#define VIDOVRDVDY      0xac
142
/*  ... */
143
#define VIDOVRDVDYOFF   0xe0
144
#define VIDDESKSTART    0xe4
145
#define VIDDESKSTRIDE   0xe8
146
#define VIDINADDR0      0xec
147
#define VIDINADDR1      0xf0
148
#define VIDINADDR2      0xf4
149
#define VIDINSTRIDE     0xf8
150
#define VIDCUROVRSTART  0xfc
151
 
152
#define INTCTRL         (0x00100000 + 0x04)
153
#define CLIP0MIN        (0x00100000 + 0x08)
154
#define CLIP0MAX        (0x00100000 + 0x0c)
155
#define DSTBASE         (0x00100000 + 0x10)
156
#define DSTFORMAT       (0x00100000 + 0x14)
157
#define SRCBASE         (0x00100000 + 0x34)
158
#define COMMANDEXTRA_2D (0x00100000 + 0x38)
159
#define CLIP1MIN        (0x00100000 + 0x4c)
160
#define CLIP1MAX        (0x00100000 + 0x50)
161
#define SRCFORMAT       (0x00100000 + 0x54)
162
#define SRCSIZE         (0x00100000 + 0x58)
163
#define SRCXY           (0x00100000 + 0x5c)
164
#define COLORBACK       (0x00100000 + 0x60)
165
#define COLORFORE       (0x00100000 + 0x64)
166
#define DSTSIZE         (0x00100000 + 0x68)
167
#define DSTXY           (0x00100000 + 0x6c)
168
#define COMMAND_2D      (0x00100000 + 0x70)
169
#define LAUNCH_2D       (0x00100000 + 0x80)
170
 
171
#define COMMAND_3D      (0x00200000 + 0x120)
172
 
173
/* register bitfields (not all, only as needed) */
174
 
175
#define BIT(x) (1UL << (x))
176
 
177
/* COMMAND_2D reg. values */
178
#define ROP_COPY        0xcc     // src
179
#define ROP_INVERT      0x55     // NOT dst
180
#define ROP_XOR         0x66     // src XOR dst
181
 
182
#define AUTOINC_DSTX                    BIT(10)
183
#define AUTOINC_DSTY                    BIT(11)
184
#define COMMAND_2D_FILLRECT             0x05
185
#define COMMAND_2D_S2S_BITBLT           0x01      // screen to screen
186
#define COMMAND_2D_H2S_BITBLT           0x03       // host to screen
187
 
188
 
189
#define COMMAND_3D_NOP                  0x00
190
#define STATUS_RETRACE                  BIT(6)
191
#define STATUS_BUSY                     BIT(9)
192
#define MISCINIT1_CLUT_INV              BIT(0)
193
#define MISCINIT1_2DBLOCK_DIS           BIT(15)
194
#define DRAMINIT0_SGRAM_NUM             BIT(26)
195
#define DRAMINIT0_SGRAM_TYPE            BIT(27)
196
#define DRAMINIT1_MEM_SDRAM             BIT(30)
197
#define VGAINIT0_VGA_DISABLE            BIT(0)
198
#define VGAINIT0_EXT_TIMING             BIT(1)
199
#define VGAINIT0_8BIT_DAC               BIT(2)
200
#define VGAINIT0_EXT_ENABLE             BIT(6)
201
#define VGAINIT0_WAKEUP_3C3             BIT(8)
202
#define VGAINIT0_LEGACY_DISABLE         BIT(9)
203
#define VGAINIT0_ALT_READBACK           BIT(10)
204
#define VGAINIT0_FAST_BLINK             BIT(11)
205
#define VGAINIT0_EXTSHIFTOUT            BIT(12)
206
#define VGAINIT0_DECODE_3C6             BIT(13)
207
#define VGAINIT0_SGRAM_HBLANK_DISABLE   BIT(22)
208
#define VGAINIT1_MASK                   0x1fffff
209
#define VIDCFG_VIDPROC_ENABLE           BIT(0)
210
#define VIDCFG_CURS_X11                 BIT(1)
211
#define VIDCFG_INTERLACE                BIT(3)
212
#define VIDCFG_HALF_MODE                BIT(4)
213
#define VIDCFG_DESK_ENABLE              BIT(7)
214
#define VIDCFG_CLUT_BYPASS              BIT(10)
215
#define VIDCFG_2X                       BIT(26)
216
#define VIDCFG_HWCURSOR_ENABLE          BIT(27)
217
#define VIDCFG_PIXFMT_SHIFT             18
218
#define DACMODE_2X                      BIT(0)
219
 
220
/* VGA rubbish, need to change this for multihead support */
221
#define MISC_W  0x3c2
222
#define MISC_R  0x3cc
223
#define SEQ_I   0x3c4
224
#define SEQ_D   0x3c5
225
#define CRT_I   0x3d4
226
#define CRT_D   0x3d5
227
#define ATT_IW  0x3c0
228
#define IS1_R   0x3da
229
#define GRA_I   0x3ce
230
#define GRA_D   0x3cf
231
 
232
#ifndef FB_ACCEL_3DFX_BANSHEE 
233
#define FB_ACCEL_3DFX_BANSHEE 31
234
#endif
235
 
236
#define TDFXF_HSYNC_ACT_HIGH    0x01
237
#define TDFXF_HSYNC_ACT_LOW     0x02
238
#define TDFXF_VSYNC_ACT_HIGH    0x04
239
#define TDFXF_VSYNC_ACT_LOW     0x08
240
#define TDFXF_LINE_DOUBLE       0x10
241
#define TDFXF_VIDEO_ENABLE      0x20
242
#define TDFXF_INTERLACE         0x40
243
 
244
#define TDFXF_HSYNC_MASK        0x03
245
#define TDFXF_VSYNC_MASK        0x0c
246
 
247
//#define TDFXFB_DEBUG 
248
#ifdef TDFXFB_DEBUG
249
#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
250
#else
251
#define DPRINTK(a,b...)
252
#endif 
253
 
254
#define PICOS2KHZ(a) (1000000000UL/(a))
255
#define KHZ2PICOS(a) (1000000000UL/(a))
256
 
257
#define BANSHEE_MAX_PIXCLOCK 270000.0
258
#define VOODOO3_MAX_PIXCLOCK 300000.0
259
#define VOODOO5_MAX_PIXCLOCK 350000.0
260
 
261
struct banshee_reg {
262
  /* VGA rubbish */
263
  unsigned char att[21];
264
  unsigned char crt[25];
265
  unsigned char gra[ 9];
266
  unsigned char misc[1];
267
  unsigned char seq[ 5];
268
 
269
  /* Banshee extensions */
270
  unsigned char ext[2];
271
  unsigned long vidcfg;
272
  unsigned long vidpll;
273
  unsigned long mempll;
274
  unsigned long gfxpll;
275
  unsigned long dacmode;
276
  unsigned long vgainit0;
277
  unsigned long vgainit1;
278
  unsigned long screensize;
279
  unsigned long stride;
280
  unsigned long cursloc;
281
  unsigned long curspataddr;
282
  unsigned long cursc0;
283
  unsigned long cursc1;
284
  unsigned long startaddr;
285
  unsigned long clip0min;
286
  unsigned long clip0max;
287
  unsigned long clip1min;
288
  unsigned long clip1max;
289
  unsigned long srcbase;
290
  unsigned long dstbase;
291
  unsigned long miscinit0;
292
};
293
 
294
struct tdfxfb_par {
295
  u32 pixclock;
296
 
297
  u32 baseline;
298
 
299
  u32 width;
300
  u32 height;
301
  u32 width_virt;
302
  u32 height_virt;
303
  u32 lpitch; /* line pitch, in bytes */
304
  u32 ppitch; /* pixel pitch, in bits */
305
  u32 bpp;
306
 
307
  u32 hdispend;
308
  u32 hsyncsta;
309
  u32 hsyncend;
310
  u32 htotal;
311
 
312
  u32 vdispend;
313
  u32 vsyncsta;
314
  u32 vsyncend;
315
  u32 vtotal;
316
 
317
  u32 video;
318
  u32 accel_flags;
319
  u32 cmap_len;
320
};
321
 
322
struct fb_info_tdfx {
323
  struct fb_info fb_info;
324
 
325
  u16 dev;
326
  u32 max_pixclock;
327
 
328
  unsigned long regbase_phys;
329
  void *regbase_virt;
330
  unsigned long regbase_size;
331
  unsigned long bufbase_phys;
332
  void *bufbase_virt;
333
  unsigned long bufbase_size;
334
  unsigned long iobase;
335
 
336
  struct { unsigned red, green, blue, pad; } palette[256];
337
  struct tdfxfb_par default_par;
338
  struct tdfxfb_par current_par;
339
  struct display disp;
340
#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)  
341
  union {
342
#ifdef FBCON_HAS_CFB16
343
    u16 cfb16[16];
344
#endif
345
#ifdef FBCON_HAS_CFB24
346
    u32 cfb24[16];
347
#endif
348
#ifdef FBCON_HAS_CFB32
349
    u32 cfb32[16];
350
#endif
351
  } fbcon_cmap;
352
#endif
353
  struct {
354
     int type;
355
     int state;
356
     int w,u,d;
357
     int x,y,redraw;
358
     unsigned long enable,disable;
359
     unsigned long cursorimage;
360
     struct timer_list timer;
361
  } cursor;
362
 
363
  spinlock_t DAClock;
364
#ifdef CONFIG_MTRR
365
  int mtrr_idx;
366
#endif
367
};
368
 
369
/*
370
 *  Frame buffer device API
371
 */
372
static int tdfxfb_get_fix(struct fb_fix_screeninfo* fix,
373
                          int con,
374
                          struct fb_info* fb);
375
static int tdfxfb_get_var(struct fb_var_screeninfo* var,
376
                          int con,
377
                          struct fb_info* fb);
378
static int tdfxfb_set_var(struct fb_var_screeninfo* var,
379
                          int con,
380
                          struct fb_info* fb);
381
static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
382
                              int con,
383
                              struct fb_info* fb);
384
static int tdfxfb_get_cmap(struct fb_cmap *cmap,
385
                           int kspc,
386
                           int con,
387
                           struct fb_info* info);
388
static int tdfxfb_set_cmap(struct fb_cmap* cmap,
389
                           int kspc,
390
                           int con,
391
                           struct fb_info* info);
392
 
393
/*
394
 *  Interface to the low level console driver
395
 */
396
static int  tdfxfb_switch_con(int con,
397
                              struct fb_info* fb);
398
static int  tdfxfb_updatevar(int con,
399
                             struct fb_info* fb);
400
static void tdfxfb_blank(int blank,
401
                         struct fb_info* fb);
402
 
403
/*
404
 *  Internal routines
405
 */
406
static void tdfxfb_set_par(struct tdfxfb_par* par,
407
                           struct fb_info_tdfx*
408
                           info);
409
static int  tdfxfb_decode_var(const struct fb_var_screeninfo *var,
410
                              struct tdfxfb_par *par,
411
                              const struct fb_info_tdfx *info);
412
static int  tdfxfb_encode_var(struct fb_var_screeninfo* var,
413
                              const struct tdfxfb_par* par,
414
                              const struct fb_info_tdfx* info);
415
static int  tdfxfb_encode_fix(struct fb_fix_screeninfo* fix,
416
                              const struct tdfxfb_par* par,
417
                              const struct fb_info_tdfx* info);
418
static void tdfxfb_set_dispsw(struct display* disp,
419
                              struct fb_info_tdfx* info,
420
                              int bpp,
421
                              int accel);
422
static int  tdfxfb_getcolreg(u_int regno,
423
                             u_int* red,
424
                             u_int* green,
425
                             u_int* blue,
426
                             u_int* transp,
427
                             struct fb_info* fb);
428
static int  tdfxfb_setcolreg(u_int regno,
429
                             u_int red,
430
                             u_int green,
431
                             u_int blue,
432
                             u_int transp,
433
                             struct fb_info* fb);
434
static void  tdfxfb_install_cmap(struct display *d,
435
                                 struct fb_info *info);
436
 
437
static void tdfxfb_hwcursor_init(void);
438
static void tdfxfb_createcursorshape(struct display* p);
439
static void tdfxfb_createcursor(struct display * p);
440
 
441
/*
442
 * do_xxx: Hardware-specific functions
443
 */
444
static void  do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i);
445
static void  do_flashcursor(unsigned long ptr);
446
static void  do_bitblt(u32 curx, u32 cury, u32 dstx,u32 dsty,
447
                      u32 width, u32 height,u32 stride,u32 bpp);
448
static void  do_fillrect(u32 x, u32 y, u32 w,u32 h,
449
                        u32 color,u32 stride,u32 bpp,u32 rop);
450
static void  do_putc(u32 fgx, u32 bgx,struct display *p,
451
                        int c, int yy,int xx);
452
static void  do_putcs(u32 fgx, u32 bgx,struct display *p,
453
                     const unsigned short *s,int count, int yy,int xx);
454
static u32 do_calc_pll(int freq, int* freq_out);
455
static void  do_write_regs(struct banshee_reg* reg);
456
static unsigned long do_lfb_size(void);
457
 
458
/*
459
 *  Interface used by the world
460
 */
461
int tdfxfb_init(void);
462
void tdfxfb_setup(char *options,
463
                  int *ints);
464
 
465
/*
466
 * PCI driver prototypes
467
 */
468
static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id);
469
static void tdfxfb_remove(struct pci_dev *pdev);
470
 
471
static int currcon = 0;
472
 
473
static struct fb_ops tdfxfb_ops = {
474
        owner:          THIS_MODULE,
475
        fb_get_fix:     tdfxfb_get_fix,
476
        fb_get_var:     tdfxfb_get_var,
477
        fb_set_var:     tdfxfb_set_var,
478
        fb_get_cmap:    tdfxfb_get_cmap,
479
        fb_set_cmap:    tdfxfb_set_cmap,
480
        fb_pan_display: tdfxfb_pan_display,
481
};
482
 
483
static struct pci_device_id tdfxfb_id_table[] __devinitdata = {
484
        { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
485
          PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
486
          0xff0000, 0 },
487
        { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
488
          PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
489
          0xff0000, 0 },
490
        { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
491
          PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
492
          0xff0000, 0 },
493
        { 0, }
494
};
495
 
496
static struct pci_driver tdfxfb_driver = {
497
        name:           "tdfxfb",
498
        id_table:       tdfxfb_id_table,
499
        probe:          tdfxfb_probe,
500
        remove:         __devexit_p(tdfxfb_remove),
501
};
502
 
503
MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
504
 
505
struct mode {
506
  char* name;
507
  struct fb_var_screeninfo var;
508
} mode;
509
 
510
/* 2.3.x kernels have a fb mode database, so supply only one backup default */
511
struct mode default_mode[] = {
512
  { "640x480-8@60", /* @ 60 Hz */
513
    {
514
      640, 480, 640, 1024, 0, 0, 8, 0,
515
      {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
516
      0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
517
      39722, 40, 24, 32, 11, 96, 2,
518
      0, FB_VMODE_NONINTERLACED
519
    }
520
  }
521
};
522
 
523
static struct fb_info_tdfx fb_info;
524
 
525
static int  noaccel = 0;
526
static int  nopan   = 0;
527
static int  nowrap  = 1;      // not implemented (yet)
528
static int  inverse = 0;
529
#ifdef CONFIG_MTRR
530
static int  nomtrr = 0;
531
#endif
532
static int  nohwcursor = 0;
533
static char __initdata fontname[40] = { 0 };
534
static char *mode_option __initdata = NULL;
535
 
536
/* -------------------------------------------------------------------------
537
 *                      Hardware-specific funcions
538
 * ------------------------------------------------------------------------- */
539
 
540
#ifdef VGA_REG_IO 
541
static inline  u8 vga_inb(u32 reg) { return inb(reg); }
542
static inline u16 vga_inw(u32 reg) { return inw(reg); }
543
static inline u16 vga_inl(u32 reg) { return inl(reg); }
544
 
545
static inline void vga_outb(u32 reg,  u8 val) { outb(val, reg); }
546
static inline void vga_outw(u32 reg, u16 val) { outw(val, reg); }
547
static inline void vga_outl(u32 reg, u32 val) { outl(val, reg); }
548
#else
549
static inline  u8 vga_inb(u32 reg) {
550
  return inb(fb_info.iobase + reg - 0x300);
551
}
552
static inline u16 vga_inw(u32 reg) {
553
  return inw(fb_info.iobase + reg - 0x300);
554
}
555
static inline u16 vga_inl(u32 reg) {
556
  return inl(fb_info.iobase + reg - 0x300);
557
}
558
 
559
static inline void vga_outb(u32 reg,  u8 val) {
560
  outb(val, fb_info.iobase + reg - 0x300);
561
}
562
static inline void vga_outw(u32 reg, u16 val) {
563
  outw(val, fb_info.iobase + reg - 0x300);
564
}
565
static inline void vga_outl(u32 reg, u32 val) {
566
  outl(val, fb_info.iobase + reg - 0x300);
567
}
568
#endif
569
 
570
static inline void gra_outb(u32 idx, u8 val) {
571
  vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
572
}
573
 
574
static inline u8 gra_inb(u32 idx) {
575
  vga_outb(GRA_I, idx); return vga_inb(GRA_D);
576
}
577
 
578
static inline void seq_outb(u32 idx, u8 val) {
579
  vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
580
}
581
 
582
static inline u8 seq_inb(u32 idx) {
583
  vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
584
}
585
 
586
static inline void crt_outb(u32 idx, u8 val) {
587
  vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
588
}
589
 
590
static inline u8 crt_inb(u32 idx) {
591
  vga_outb(CRT_I, idx); return vga_inb(CRT_D);
592
}
593
 
594
static inline void att_outb(u32 idx, u8 val) {
595
  unsigned char tmp;
596
  tmp = vga_inb(IS1_R);
597
  vga_outb(ATT_IW, idx);
598
  vga_outb(ATT_IW, val);
599
}
600
 
601
static inline u8 att_inb(u32 idx) {
602
  unsigned char tmp;
603
  tmp = vga_inb(IS1_R);
604
  vga_outb(ATT_IW, idx);
605
  return vga_inb(ATT_IW);
606
}
607
 
608
static inline void vga_disable_video(void) {
609
  unsigned char s;
610
  s = seq_inb(0x01) | 0x20;
611
  seq_outb(0x00, 0x01);
612
  seq_outb(0x01, s);
613
  seq_outb(0x00, 0x03);
614
}
615
 
616
static inline void vga_enable_video(void) {
617
  unsigned char s;
618
  s = seq_inb(0x01) & 0xdf;
619
  seq_outb(0x00, 0x01);
620
  seq_outb(0x01, s);
621
  seq_outb(0x00, 0x03);
622
}
623
 
624
static inline void vga_disable_palette(void) {
625
  vga_inb(IS1_R);
626
  vga_outb(ATT_IW, 0x00);
627
}
628
 
629
static inline void vga_enable_palette(void) {
630
  vga_inb(IS1_R);
631
  vga_outb(ATT_IW, 0x20);
632
}
633
 
634
static inline u32 tdfx_inl(unsigned int reg) {
635
  return readl(fb_info.regbase_virt + reg);
636
}
637
 
638
static inline void tdfx_outl(unsigned int reg, u32 val) {
639
  writel(val, fb_info.regbase_virt + reg);
640
}
641
 
642
static inline void banshee_make_room(int size) {
643
  while((tdfx_inl(STATUS) & 0x1f) < size);
644
}
645
 
646
static inline void banshee_wait_idle(void) {
647
  int i = 0;
648
 
649
  banshee_make_room(1);
650
  tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
651
 
652
  while(1) {
653
    i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
654
    if(i == 3) break;
655
  }
656
}
657
/*
658
 * Set the color of a palette entry in 8bpp mode
659
 */
660
static inline void do_setpalentry(unsigned regno, u32 c) {
661
   banshee_make_room(2); tdfx_outl(DACADDR,  regno); tdfx_outl(DACDATA,  c); }
662
 
663
/*
664
 * Set the starting position of the visible screen to var->yoffset
665
 */
666
static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_tdfx *i)
667
{
668
    u32 addr;
669
    addr = var->yoffset*i->current_par.lpitch;
670
    banshee_make_room(1);
671
    tdfx_outl(VIDDESKSTART, addr);
672
}
673
 
674
/*
675
 * Invert the hardware cursor image (timerfunc)
676
 */
677
static void do_flashcursor(unsigned long ptr)
678
{
679
   struct fb_info_tdfx* i=(struct fb_info_tdfx *)ptr;
680
   unsigned long flags;
681
 
682
   spin_lock_irqsave(&i->DAClock, flags);
683
   banshee_make_room(1);
684
   tdfx_outl( VIDPROCCFG, tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE );
685
   i->cursor.timer.expires=jiffies+HZ/2;
686
   add_timer(&i->cursor.timer);
687
   spin_unlock_irqrestore(&i->DAClock, flags);
688
}
689
 
690
/*
691
 * FillRect 2D command (solidfill or invert (via ROP_XOR))
692
 */
693
static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
694
                        u32 color, u32 stride, u32 bpp, u32 rop) {
695
 
696
   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
697
 
698
   banshee_make_room(5);
699
   tdfx_outl(DSTFORMAT, fmt);
700
   tdfx_outl(COLORFORE, color);
701
   tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
702
   tdfx_outl(DSTSIZE,    w | (h << 16));
703
   tdfx_outl(LAUNCH_2D,  x | (y << 16));
704
   banshee_wait_idle();
705
}
706
 
707
/*
708
 * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
709
 */
710
 
711
static void do_bitblt(u32 curx,
712
                           u32 cury,
713
                           u32 dstx,
714
                           u32 dsty,
715
                           u32 width,
716
                           u32 height,
717
                           u32 stride,
718
                           u32 bpp) {
719
 
720
   u32 blitcmd = COMMAND_2D_S2S_BITBLT | (ROP_COPY << 24);
721
   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
722
 
723
   if (curx <= dstx) {
724
     //-X 
725
     blitcmd |= BIT(14);
726
     curx += width-1;
727
     dstx += width-1;
728
   }
729
   if (cury <= dsty) {
730
     //-Y  
731
     blitcmd |= BIT(15);
732
     cury += height-1;
733
     dsty += height-1;
734
   }
735
 
736
   banshee_make_room(6);
737
 
738
   tdfx_outl(SRCFORMAT, fmt);
739
   tdfx_outl(DSTFORMAT, fmt);
740
   tdfx_outl(COMMAND_2D, blitcmd);
741
   tdfx_outl(DSTSIZE,   width | (height << 16));
742
   tdfx_outl(DSTXY,     dstx | (dsty << 16));
743
   tdfx_outl(LAUNCH_2D, curx | (cury << 16));
744
   banshee_wait_idle();
745
}
746
 
747
static void do_putc(u32 fgx, u32 bgx,
748
                         struct display *p,
749
                         int c, int yy,int xx)
750
{
751
   int i;
752
   int stride=fb_info.current_par.lpitch;
753
   u32 bpp=fb_info.current_par.bpp;
754
   int fw=(fontwidth(p)+7)>>3;
755
   u8 *chardata=p->fontdata+(c&p->charmask)*fontheight(p)*fw;
756
   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
757
 
758
   xx *= fontwidth(p);
759
   yy *= fontheight(p);
760
 
761
   banshee_make_room(8+((fontheight(p)*fw+3)>>2) );
762
   tdfx_outl(COLORFORE, fgx);
763
   tdfx_outl(COLORBACK, bgx);
764
   tdfx_outl(SRCXY,     0);
765
   tdfx_outl(DSTXY,     xx | (yy << 16));
766
   tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
767
#ifdef __BIG_ENDIAN
768
   tdfx_outl(SRCFORMAT, 0x400000 | BIT(20) );
769
#else
770
   tdfx_outl(SRCFORMAT, 0x400000);
771
#endif
772
   tdfx_outl(DSTFORMAT, fmt);
773
   tdfx_outl(DSTSIZE,   fontwidth(p) | (fontheight(p) << 16));
774
   i=fontheight(p);
775
   switch (fw) {
776
    case 1:
777
     while (i>=4) {
778
         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
779
         chardata+=4;
780
         i-=4;
781
     }
782
     switch (i) {
783
      case 0: break;
784
      case 1:  tdfx_outl(LAUNCH_2D,*chardata); break;
785
      case 2:  tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
786
      case 3:  tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
787
     }
788
     break;
789
   case 2:
790
     while (i>=2) {
791
         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
792
         chardata+=4;
793
         i-=2;
794
     }
795
     if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata);
796
     break;
797
   default:
798
     // Is there a font with width more that 16 pixels ?
799
     for (i=fontheight(p);i>0;i--) {
800
         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
801
         chardata+=4;
802
     }
803
     break;
804
   }
805
   banshee_wait_idle();
806
}
807
 
808
static void do_putcs(u32 fgx, u32 bgx,
809
                          struct display *p,
810
                          const unsigned short *s,
811
                          int count, int yy,int xx)
812
{
813
   int i;
814
   int stride=fb_info.current_par.lpitch;
815
   u32 bpp=fb_info.current_par.bpp;
816
   int fw=(fontwidth(p)+7)>>3;
817
   int w=fontwidth(p);
818
   int h=fontheight(p);
819
   int regsneed=1+((h*fw+3)>>2);
820
   u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
821
 
822
   xx *= w;
823
   yy = (yy*h) << 16;
824
   banshee_make_room(8);
825
 
826
   tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
827
   tdfx_outl(COLORFORE, fgx);
828
   tdfx_outl(COLORBACK, bgx);
829
#ifdef __BIG_ENDIAN
830
   tdfx_outl(SRCFORMAT, 0x400000 | BIT(20) );
831
#else
832
   tdfx_outl(SRCFORMAT, 0x400000);
833
#endif   
834
   tdfx_outl(DSTFORMAT, fmt);
835
   tdfx_outl(DSTSIZE, w | (h << 16));
836
   tdfx_outl(SRCXY,     0);
837
   tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (ROP_COPY << 24));
838
 
839
   while (count--) {
840
      u8 *chardata=p->fontdata+(scr_readw(s++) & p->charmask)*h*fw;
841
 
842
      banshee_make_room(regsneed);
843
      tdfx_outl(DSTXY, xx | yy);
844
      xx+=w;
845
 
846
      i=h;
847
      switch (fw) {
848
       case 1:
849
        while (i>=4) {
850
           tdfx_outl(LAUNCH_2D,*(u32*)chardata);
851
           chardata+=4;
852
           i-=4;
853
        }
854
        switch (i) {
855
          case 0: break;
856
          case 1:  tdfx_outl(LAUNCH_2D,*chardata); break;
857
          case 2:  tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
858
          case 3:  tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
859
        }
860
        break;
861
       case 2:
862
        while (i>=2) {
863
         tdfx_outl(LAUNCH_2D,*(u32*)chardata);
864
         chardata+=4;
865
         i-=2;
866
        }
867
        if (i) tdfx_outl(LAUNCH_2D,*(u16*)chardata);
868
        break;
869
       default:
870
       // Is there a font with width more that 16 pixels ?
871
        for (;i>0;i--) {
872
          tdfx_outl(LAUNCH_2D,*(u32*)chardata);
873
          chardata+=4;
874
        }
875
        break;
876
     }
877
   }
878
   banshee_wait_idle();
879
}
880
 
881
static u32 do_calc_pll(int freq, int* freq_out) {
882
  int m, n, k, best_m, best_n, best_k, f_cur, best_error;
883
  int fref = 14318;
884
 
885
  /* this really could be done with more intelligence --
886
     255*63*4 = 64260 iterations is silly */
887
  best_error = freq;
888
  best_n = best_m = best_k = 0;
889
  for(n = 1; n < 256; n++) {
890
    for(m = 1; m < 64; m++) {
891
      for(k = 0; k < 4; k++) {
892
        f_cur = fref*(n + 2)/(m + 2)/(1 << k);
893
        if(abs(f_cur - freq) < best_error) {
894
          best_error = abs(f_cur-freq);
895
          best_n = n;
896
          best_m = m;
897
          best_k = k;
898
        }
899
      }
900
    }
901
  }
902
  n = best_n;
903
  m = best_m;
904
  k = best_k;
905
  *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
906
 
907
  return (n << 8) | (m << 2) | k;
908
}
909
 
910
static void do_write_regs(struct banshee_reg* reg) {
911
  int i;
912
 
913
  banshee_wait_idle();
914
 
915
  tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
916
 
917
  crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
918
 
919
  banshee_make_room(3);
920
  tdfx_outl(VGAINIT1,      reg->vgainit1 &  0x001FFFFF);
921
  tdfx_outl(VIDPROCCFG,    reg->vidcfg   & ~0x00000001);
922
#if 0
923
  tdfx_outl(PLLCTRL1,      reg->mempll);
924
  tdfx_outl(PLLCTRL2,      reg->gfxpll);
925
#endif
926
  tdfx_outl(PLLCTRL0,      reg->vidpll);
927
 
928
  vga_outb(MISC_W, reg->misc[0x00] | 0x01);
929
 
930
  for(i = 0; i < 5; i++)
931
    seq_outb(i, reg->seq[i]);
932
 
933
  for(i = 0; i < 25; i++)
934
    crt_outb(i, reg->crt[i]);
935
 
936
  for(i = 0; i < 9; i++)
937
    gra_outb(i, reg->gra[i]);
938
 
939
  for(i = 0; i < 21; i++)
940
    att_outb(i, reg->att[i]);
941
 
942
  crt_outb(0x1a, reg->ext[0]);
943
  crt_outb(0x1b, reg->ext[1]);
944
 
945
  vga_enable_palette();
946
  vga_enable_video();
947
 
948
  banshee_make_room(11);
949
  tdfx_outl(VGAINIT0,      reg->vgainit0);
950
  tdfx_outl(DACMODE,       reg->dacmode);
951
  tdfx_outl(VIDDESKSTRIDE, reg->stride);
952
  if (nohwcursor) {
953
     tdfx_outl(HWCURPATADDR,  0);
954
  } else {
955
     tdfx_outl(HWCURPATADDR,  reg->curspataddr);
956
     tdfx_outl(HWCURC0,       reg->cursc0);
957
     tdfx_outl(HWCURC1,       reg->cursc1);
958
     tdfx_outl(HWCURLOC,      reg->cursloc);
959
  }
960
 
961
  tdfx_outl(VIDSCREENSIZE, reg->screensize);
962
  tdfx_outl(VIDDESKSTART,  reg->startaddr);
963
  tdfx_outl(VIDPROCCFG,    reg->vidcfg);
964
  tdfx_outl(VGAINIT1,      reg->vgainit1);
965
  tdfx_outl(MISCINIT0,     reg->miscinit0);
966
 
967
  banshee_make_room(8);
968
  tdfx_outl(SRCBASE,         reg->srcbase);
969
  tdfx_outl(DSTBASE,         reg->dstbase);
970
  tdfx_outl(COMMANDEXTRA_2D, 0);
971
  tdfx_outl(CLIP0MIN,        0);
972
  tdfx_outl(CLIP0MAX,        0x0fff0fff);
973
  tdfx_outl(CLIP1MIN,        0);
974
  tdfx_outl(CLIP1MAX,        0x0fff0fff);
975
  tdfx_outl(SRCXY, 0);
976
 
977
  banshee_wait_idle();
978
}
979
 
980
static unsigned long do_lfb_size(void) {
981
  u32 draminit0 = 0;
982
  u32 draminit1 = 0;
983
  u32 miscinit1 = 0;
984
  u32 lfbsize   = 0;
985
  int sgram_p     = 0;
986
 
987
  draminit0 = tdfx_inl(DRAMINIT0);
988
  draminit1 = tdfx_inl(DRAMINIT1);
989
 
990
  if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
991
      (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) {
992
    sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
993
 
994
    lfbsize = sgram_p ?
995
      (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) *
996
       ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
997
      16 * 1024 * 1024;
998
  } else {
999
    /* Voodoo4/5 */
1000
    u32 chips, psize, banks;
1001
 
1002
    chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
1003
    psize = 1 << ((draminit0 & 0x38000000) >> 28);
1004
    banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
1005
    lfbsize = chips * psize * banks;
1006
    lfbsize <<= 20;
1007
  }
1008
 
1009
  /* disable block writes for SDRAM (why?) */
1010
  miscinit1 = tdfx_inl(MISCINIT1);
1011
  miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
1012
  miscinit1 |= MISCINIT1_CLUT_INV;
1013
 
1014
  banshee_make_room(1);
1015
  tdfx_outl(MISCINIT1, miscinit1);
1016
 
1017
  return lfbsize;
1018
}
1019
 
1020
/* -------------------------------------------------------------------------
1021
 *              Hardware independent part, interface to the world
1022
 * ------------------------------------------------------------------------- */
1023
 
1024
#define tdfx_cfb24_putc  tdfx_cfb32_putc
1025
#define tdfx_cfb24_putcs tdfx_cfb32_putcs
1026
#define tdfx_cfb24_clear tdfx_cfb32_clear
1027
 
1028
static void tdfx_cfbX_clear_margins(struct vc_data* conp, struct display* p,
1029
                                    int bottom_only)
1030
{
1031
   unsigned int cw=fontwidth(p);
1032
   unsigned int ch=fontheight(p);
1033
   unsigned int rw=p->var.xres % cw;   // it be in a non-standard mode or not?
1034
   unsigned int bh=p->var.yres % ch;
1035
   unsigned int rs=p->var.xres - rw;
1036
   unsigned int bs=p->var.yres - bh;
1037
 
1038
   if (!bottom_only && rw) {
1039
      do_fillrect( p->var.xoffset+rs, 0,
1040
                  rw, p->var.yres_virtual, 0,
1041
                  fb_info.current_par.lpitch,
1042
                  fb_info.current_par.bpp, ROP_COPY);
1043
   }
1044
 
1045
   if (bh) {
1046
      do_fillrect( p->var.xoffset, p->var.yoffset+bs,
1047
                  rs, bh, 0,
1048
                  fb_info.current_par.lpitch,
1049
                  fb_info.current_par.bpp, ROP_COPY);
1050
   }
1051
}
1052
static void tdfx_cfbX_bmove(struct display* p,
1053
                                int sy,
1054
                                int sx,
1055
                                int dy,
1056
                                int dx,
1057
                                int height,
1058
                                int width) {
1059
   do_bitblt(fontwidth(p)*sx,
1060
                 fontheight(p)*sy,
1061
                 fontwidth(p)*dx,
1062
                 fontheight(p)*dy,
1063
                 fontwidth(p)*width,
1064
                 fontheight(p)*height,
1065
                 fb_info.current_par.lpitch,
1066
                 fb_info.current_par.bpp);
1067
}
1068
static void tdfx_cfb8_putc(struct vc_data* conp,
1069
                               struct display* p,
1070
                               int c, int yy,int xx)
1071
{
1072
   u32 fgx,bgx;
1073
   fgx=attr_fgcol(p, c);
1074
   bgx=attr_bgcol(p, c);
1075
   do_putc( fgx,bgx,p,c,yy,xx );
1076
}
1077
 
1078
static void tdfx_cfb16_putc(struct vc_data* conp,
1079
                               struct display* p,
1080
                               int c, int yy,int xx)
1081
{
1082
   u32 fgx,bgx;
1083
   fgx=((u16*)p->dispsw_data)[attr_fgcol(p,c)];
1084
   bgx=((u16*)p->dispsw_data)[attr_bgcol(p,c)];
1085
   do_putc( fgx,bgx,p,c,yy,xx );
1086
}
1087
 
1088
static void tdfx_cfb32_putc(struct vc_data* conp,
1089
                               struct display* p,
1090
                               int c, int yy,int xx)
1091
{
1092
   u32 fgx,bgx;
1093
   fgx=((u32*)p->dispsw_data)[attr_fgcol(p,c)];
1094
   bgx=((u32*)p->dispsw_data)[attr_bgcol(p,c)];
1095
   do_putc( fgx,bgx,p,c,yy,xx );
1096
}
1097
static void tdfx_cfb8_putcs(struct vc_data* conp,
1098
                            struct display* p,
1099
                            const unsigned short *s,int count,int yy,int xx)
1100
{
1101
   u16 c = scr_readw(s);
1102
   u32 fgx = attr_fgcol(p, c);
1103
   u32 bgx = attr_bgcol(p, c);
1104
   do_putcs( fgx,bgx,p,s,count,yy,xx );
1105
}
1106
static void tdfx_cfb16_putcs(struct vc_data* conp,
1107
                            struct display* p,
1108
                            const unsigned short *s,int count,int yy,int xx)
1109
{
1110
   u16 c = scr_readw(s);
1111
   u32 fgx = ((u16*)p->dispsw_data)[attr_fgcol(p, c)];
1112
   u32 bgx = ((u16*)p->dispsw_data)[attr_bgcol(p, c)];
1113
   do_putcs( fgx,bgx,p,s,count,yy,xx );
1114
}
1115
static void tdfx_cfb32_putcs(struct vc_data* conp,
1116
                            struct display* p,
1117
                            const unsigned short *s,int count,int yy,int xx)
1118
{
1119
   u16 c = scr_readw(s);
1120
   u32 fgx = ((u32*)p->dispsw_data)[attr_fgcol(p, c)];
1121
   u32 bgx = ((u32*)p->dispsw_data)[attr_bgcol(p, c)];
1122
   do_putcs( fgx,bgx,p,s,count,yy,xx );
1123
}
1124
 
1125
static void tdfx_cfb8_clear(struct vc_data* conp,
1126
                                struct display* p,
1127
                                int sy,
1128
                                int sx,
1129
                                int height,
1130
                                int width) {
1131
  u32 bg;
1132
 
1133
  bg = attr_bgcol_ec(p,conp);
1134
  do_fillrect(fontwidth(p)*sx,
1135
                   fontheight(p)*sy,
1136
                   fontwidth(p)*width,
1137
                   fontheight(p)*height,
1138
                   bg,
1139
                   fb_info.current_par.lpitch,
1140
                   fb_info.current_par.bpp,ROP_COPY);
1141
}
1142
 
1143
static void tdfx_cfb16_clear(struct vc_data* conp,
1144
                                struct display* p,
1145
                                int sy,
1146
                                int sx,
1147
                                int height,
1148
                                int width) {
1149
  u32 bg;
1150
 
1151
  bg = ((u16*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
1152
  do_fillrect(fontwidth(p)*sx,
1153
                   fontheight(p)*sy,
1154
                   fontwidth(p)*width,
1155
                   fontheight(p)*height,
1156
                   bg,
1157
                   fb_info.current_par.lpitch,
1158
                   fb_info.current_par.bpp,ROP_COPY);
1159
}
1160
 
1161
static void tdfx_cfb32_clear(struct vc_data* conp,
1162
                                struct display* p,
1163
                                int sy,
1164
                                int sx,
1165
                                int height,
1166
                                int width) {
1167
  u32 bg;
1168
 
1169
  bg = ((u32*)p->dispsw_data)[attr_bgcol_ec(p,conp)];
1170
  do_fillrect(fontwidth(p)*sx,
1171
                   fontheight(p)*sy,
1172
                   fontwidth(p)*width,
1173
                   fontheight(p)*height,
1174
                   bg,
1175
                   fb_info.current_par.lpitch,
1176
                   fb_info.current_par.bpp,ROP_COPY);
1177
}
1178
static void tdfx_cfbX_revc(struct display *p, int xx, int yy)
1179
{
1180
   int bpp=fb_info.current_par.bpp;
1181
 
1182
   do_fillrect( xx * fontwidth(p), yy * fontheight(p),
1183
                fontwidth(p), fontheight(p),
1184
                (bpp==8) ? 0x0f : 0xffffffff,
1185
                fb_info.current_par.lpitch, bpp, ROP_XOR);
1186
 
1187
}
1188
static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y)
1189
{
1190
   unsigned long flags;
1191
   int tip;
1192
   struct fb_info_tdfx *info=(struct fb_info_tdfx *)p->fb_info;
1193
 
1194
   tip=p->conp->vc_cursor_type & CUR_HWMASK;
1195
   if (mode==CM_ERASE) {
1196
        if (info->cursor.state != CM_ERASE) {
1197
             spin_lock_irqsave(&info->DAClock,flags);
1198
             info->cursor.state=CM_ERASE;
1199
             del_timer(&(info->cursor.timer));
1200
             tdfx_outl(VIDPROCCFG,info->cursor.disable);
1201
             spin_unlock_irqrestore(&info->DAClock,flags);
1202
        }
1203
        return;
1204
   }
1205
   if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
1206
         tdfxfb_createcursor(p);
1207
   x *= fontwidth(p);
1208
   y *= fontheight(p);
1209
   y -= p->var.yoffset;
1210
   spin_lock_irqsave(&info->DAClock,flags);
1211
   if ((x!=info->cursor.x) ||
1212
      (y!=info->cursor.y) ||
1213
      (info->cursor.redraw)) {
1214
          info->cursor.x=x;
1215
          info->cursor.y=y;
1216
          info->cursor.redraw=0;
1217
          x += 63;
1218
          y += 63;
1219
          banshee_make_room(2);
1220
          tdfx_outl(VIDPROCCFG, info->cursor.disable);
1221
          tdfx_outl(HWCURLOC, (y << 16) + x);
1222
          /* fix cursor color - XFree86 forgets to restore it properly */
1223
          tdfx_outl(HWCURC0, 0);
1224
          tdfx_outl(HWCURC1, 0xffffff);
1225
   }
1226
   info->cursor.state = CM_DRAW;
1227
   mod_timer(&info->cursor.timer,jiffies+HZ/2);
1228
   banshee_make_room(1);
1229
   tdfx_outl(VIDPROCCFG, info->cursor.enable);
1230
   spin_unlock_irqrestore(&info->DAClock,flags);
1231
   return;
1232
}
1233
#ifdef FBCON_HAS_CFB8
1234
static struct display_switch fbcon_banshee8 = {
1235
   setup:               fbcon_cfb8_setup,
1236
   bmove:               tdfx_cfbX_bmove,
1237
   clear:               tdfx_cfb8_clear,
1238
   putc:                tdfx_cfb8_putc,
1239
   putcs:               tdfx_cfb8_putcs,
1240
   revc:                tdfx_cfbX_revc,
1241
   cursor:              tdfx_cfbX_cursor,
1242
   clear_margins:       tdfx_cfbX_clear_margins,
1243
   fontwidthmask:       FONTWIDTHRANGE(8, 12)
1244
};
1245
#endif
1246
#ifdef FBCON_HAS_CFB16
1247
static struct display_switch fbcon_banshee16 = {
1248
   setup:               fbcon_cfb16_setup,
1249
   bmove:               tdfx_cfbX_bmove,
1250
   clear:               tdfx_cfb16_clear,
1251
   putc:                tdfx_cfb16_putc,
1252
   putcs:               tdfx_cfb16_putcs,
1253
   revc:                tdfx_cfbX_revc,
1254
   cursor:              tdfx_cfbX_cursor,
1255
   clear_margins:       tdfx_cfbX_clear_margins,
1256
   fontwidthmask:       FONTWIDTHRANGE(8, 12)
1257
};
1258
#endif
1259
#ifdef FBCON_HAS_CFB24
1260
static struct display_switch fbcon_banshee24 = {
1261
   setup:               fbcon_cfb24_setup,
1262
   bmove:               tdfx_cfbX_bmove,
1263
   clear:               tdfx_cfb24_clear,
1264
   putc:                tdfx_cfb24_putc,
1265
   putcs:               tdfx_cfb24_putcs,
1266
   revc:                tdfx_cfbX_revc,
1267
   cursor:              tdfx_cfbX_cursor,
1268
   clear_margins:       tdfx_cfbX_clear_margins,
1269
   fontwidthmask:       FONTWIDTHRANGE(8, 12)
1270
};
1271
#endif
1272
#ifdef FBCON_HAS_CFB32
1273
static struct display_switch fbcon_banshee32 = {
1274
   setup:               fbcon_cfb32_setup,
1275
   bmove:               tdfx_cfbX_bmove,
1276
   clear:               tdfx_cfb32_clear,
1277
   putc:                tdfx_cfb32_putc,
1278
   putcs:               tdfx_cfb32_putcs,
1279
   revc:                tdfx_cfbX_revc,
1280
   cursor:              tdfx_cfbX_cursor,
1281
   clear_margins:       tdfx_cfbX_clear_margins,
1282
   fontwidthmask:       FONTWIDTHRANGE(8, 12)
1283
};
1284
#endif
1285
 
1286
/* ------------------------------------------------------------------------- */
1287
 
1288
static void tdfxfb_set_par(struct tdfxfb_par* par,
1289
                           struct fb_info_tdfx*     info) {
1290
  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
1291
  struct banshee_reg reg;
1292
  u32 cpp;
1293
  u32 hd, hs, he, ht, hbs, hbe;
1294
  u32 vd, vs, ve, vt, vbs, vbe;
1295
  u32 wd;
1296
  int fout;
1297
  int freq;
1298
 
1299
  memset(&reg, 0, sizeof(reg));
1300
 
1301
  cpp = (par->bpp + 7)/8;
1302
 
1303
  reg.vidcfg =
1304
    VIDCFG_VIDPROC_ENABLE |
1305
    VIDCFG_DESK_ENABLE    |
1306
    VIDCFG_CURS_X11 |
1307
    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
1308
    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
1309
 
1310
  /* PLL settings */
1311
  freq = par->pixclock;
1312
 
1313
  reg.dacmode = 0;
1314
  reg.vidcfg  &= ~VIDCFG_2X;
1315
 
1316
  if(freq > i->max_pixclock/2) {
1317
    freq = freq > i->max_pixclock ? i->max_pixclock : freq;
1318
    reg.dacmode |= DACMODE_2X;
1319
    reg.vidcfg  |= VIDCFG_2X;
1320
    par->hdispend >>= 1;
1321
    par->hsyncsta >>= 1;
1322
    par->hsyncend >>= 1;
1323
    par->htotal   >>= 1;
1324
  }
1325
  wd = (par->hdispend >> 3) - 1;
1326
 
1327
  hd  = (par->hdispend >> 3) - 1;
1328
  hs  = (par->hsyncsta >> 3) - 1;
1329
  he  = (par->hsyncend >> 3) - 1;
1330
  ht  = (par->htotal   >> 3) - 1;
1331
  hbs = hd;
1332
  hbe = ht;
1333
 
1334
  if (par->video & TDFXF_LINE_DOUBLE) {
1335
    vd = (par->vdispend << 1) - 1;
1336
    vs = (par->vsyncsta << 1) - 1;
1337
    ve = (par->vsyncend << 1) - 1;
1338
    vt = (par->vtotal   << 1) - 2;
1339
  } else {
1340
    vd = par->vdispend - 1;
1341
    vs = par->vsyncsta - 1;
1342
    ve = par->vsyncend - 1;
1343
    vt = par->vtotal   - 2;
1344
  }
1345
  vbs = vd;
1346
  vbe = vt;
1347
 
1348
  /* this is all pretty standard VGA register stuffing */
1349
  reg.misc[0x00] =
1350
    0x0f |
1351
    (par->hdispend < 400 ? 0xa0 :
1352
     par->hdispend < 480 ? 0x60 :
1353
     par->hdispend < 768 ? 0xe0 : 0x20);
1354
 
1355
  reg.gra[0x00] = 0x00;
1356
  reg.gra[0x01] = 0x00;
1357
  reg.gra[0x02] = 0x00;
1358
  reg.gra[0x03] = 0x00;
1359
  reg.gra[0x04] = 0x00;
1360
  reg.gra[0x05] = 0x40;
1361
  reg.gra[0x06] = 0x05;
1362
  reg.gra[0x07] = 0x0f;
1363
  reg.gra[0x08] = 0xff;
1364
 
1365
  reg.att[0x00] = 0x00;
1366
  reg.att[0x01] = 0x01;
1367
  reg.att[0x02] = 0x02;
1368
  reg.att[0x03] = 0x03;
1369
  reg.att[0x04] = 0x04;
1370
  reg.att[0x05] = 0x05;
1371
  reg.att[0x06] = 0x06;
1372
  reg.att[0x07] = 0x07;
1373
  reg.att[0x08] = 0x08;
1374
  reg.att[0x09] = 0x09;
1375
  reg.att[0x0a] = 0x0a;
1376
  reg.att[0x0b] = 0x0b;
1377
  reg.att[0x0c] = 0x0c;
1378
  reg.att[0x0d] = 0x0d;
1379
  reg.att[0x0e] = 0x0e;
1380
  reg.att[0x0f] = 0x0f;
1381
  reg.att[0x10] = 0x41;
1382
  reg.att[0x11] = 0x00;
1383
  reg.att[0x12] = 0x0f;
1384
  reg.att[0x13] = 0x00;
1385
  reg.att[0x14] = 0x00;
1386
 
1387
  reg.seq[0x00] = 0x03;
1388
  reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
1389
  reg.seq[0x02] = 0x0f;
1390
  reg.seq[0x03] = 0x00;
1391
  reg.seq[0x04] = 0x0e;
1392
 
1393
  reg.crt[0x00] = ht - 4;
1394
  reg.crt[0x01] = hd;
1395
  reg.crt[0x02] = hbs;
1396
  reg.crt[0x03] = 0x80 | (hbe & 0x1f);
1397
  reg.crt[0x04] = hs;
1398
  reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
1399
  reg.crt[0x06] = vt;
1400
  reg.crt[0x07] =
1401
    ((vs & 0x200) >> 2) |
1402
    ((vd & 0x200) >> 3) |
1403
    ((vt & 0x200) >> 4) |
1404
    0x10 |
1405
    ((vbs & 0x100) >> 5) |
1406
    ((vs  & 0x100) >> 6) |
1407
    ((vd  & 0x100) >> 7) |
1408
    ((vt  & 0x100) >> 8);
1409
  reg.crt[0x08] = 0x00;
1410
  reg.crt[0x09] =
1411
    0x40 |
1412
    ((vbs & 0x200) >> 4);
1413
  reg.crt[0x0a] = 0x00;
1414
  reg.crt[0x0b] = 0x00;
1415
  reg.crt[0x0c] = 0x00;
1416
  reg.crt[0x0d] = 0x00;
1417
  reg.crt[0x0e] = 0x00;
1418
  reg.crt[0x0f] = 0x00;
1419
  reg.crt[0x10] = vs;
1420
  reg.crt[0x11] = (ve & 0x0f) | 0x20;
1421
  reg.crt[0x12] = vd;
1422
  reg.crt[0x13] = wd;
1423
  reg.crt[0x14] = 0x00;
1424
  reg.crt[0x15] = vbs;
1425
  reg.crt[0x16] = vbe + 1;
1426
  reg.crt[0x17] = 0xc3;
1427
  reg.crt[0x18] = 0xff;
1428
 
1429
  /* Banshee's nonvga stuff */
1430
  reg.ext[0x00] = (((ht  & 0x100) >> 8) |
1431
                   ((hd  & 0x100) >> 6) |
1432
                   ((hbs & 0x100) >> 4) |
1433
                   ((hbe &  0x40) >> 1) |
1434
                   ((hs  & 0x100) >> 2) |
1435
                   ((he  &  0x20) << 2));
1436
  reg.ext[0x01] = (((vt  & 0x400) >> 10) |
1437
                   ((vd  & 0x400) >>  8) |
1438
                   ((vbs & 0x400) >>  6) |
1439
                   ((vbe & 0x400) >>  4));
1440
 
1441
  reg.vgainit0 =
1442
    VGAINIT0_8BIT_DAC     |
1443
    VGAINIT0_EXT_ENABLE   |
1444
    VGAINIT0_WAKEUP_3C3   |
1445
    VGAINIT0_ALT_READBACK |
1446
    VGAINIT0_EXTSHIFTOUT;
1447
  reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
1448
 
1449
  reg.stride    = par->width*cpp;
1450
  reg.cursloc   = 0;
1451
 
1452
  reg.cursc0    = 0;
1453
  reg.cursc1    = 0xffffff;
1454
 
1455
  reg.curspataddr = fb_info.cursor.cursorimage;
1456
 
1457
  reg.startaddr = par->baseline*reg.stride;
1458
  reg.srcbase   = reg.startaddr;
1459
  reg.dstbase   = reg.startaddr;
1460
 
1461
  reg.vidpll = do_calc_pll(freq, &fout);
1462
#if 0
1463
  reg.mempll = do_calc_pll(..., &fout);
1464
  reg.gfxpll = do_calc_pll(..., &fout);
1465
#endif
1466
 
1467
  if (par->video & TDFXF_LINE_DOUBLE) {
1468
    reg.screensize = par->width | (par->height << 13);
1469
    reg.vidcfg |= VIDCFG_HALF_MODE;
1470
    reg.crt[0x09] |= 0x80;
1471
  } else {
1472
    reg.screensize = par->width | (par->height << 12);
1473
    reg.vidcfg &= ~VIDCFG_HALF_MODE;
1474
  }
1475
  if (par->video & TDFXF_INTERLACE)
1476
    reg.vidcfg |= VIDCFG_INTERLACE;
1477
 
1478
  fb_info.cursor.enable=reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
1479
  fb_info.cursor.disable=reg.vidcfg;
1480
 
1481
  reg.miscinit0 = tdfx_inl(MISCINIT0);
1482
 
1483
#if defined(__BIG_ENDIAN)
1484
  switch (par->bpp) {
1485
    case 8:
1486
    case 24:
1487
      reg.miscinit0 &= ~(1 << 30);
1488
      reg.miscinit0 &= ~(1 << 31);
1489
      break;
1490
    case 16:
1491
      reg.miscinit0 |= (1 << 30);
1492
      reg.miscinit0 |= (1 << 31);
1493
      break;
1494
    case 32:
1495
      reg.miscinit0 |= (1 << 30);
1496
      reg.miscinit0 &= ~(1 << 31);
1497
      break;
1498
  }
1499
#endif
1500
 
1501
  do_write_regs(&reg);
1502
  if (reg.vidcfg & VIDCFG_2X) {
1503
    par->hdispend <<= 1;
1504
    par->hsyncsta <<= 1;
1505
    par->hsyncend <<= 1;
1506
    par->htotal   <<= 1;
1507
  }
1508
  i->current_par = *par;
1509
}
1510
 
1511
static int tdfxfb_decode_var(const struct fb_var_screeninfo* var,
1512
                             struct tdfxfb_par*              par,
1513
                             const struct fb_info_tdfx*      info) {
1514
  struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
1515
 
1516
  if(var->bits_per_pixel != 8  &&
1517
     var->bits_per_pixel != 16 &&
1518
     var->bits_per_pixel != 24 &&
1519
     var->bits_per_pixel != 32) {
1520
    DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
1521
    return -EINVAL;
1522
  }
1523
 
1524
  if(var->xoffset) {
1525
    DPRINTK("xoffset not supported\n");
1526
    return -EINVAL;
1527
  }
1528
 
1529
  if(var->xres != var->xres_virtual) {
1530
    DPRINTK("virtual x resolution != physical x resolution not supported\n");
1531
    return -EINVAL;
1532
  }
1533
 
1534
  if(var->yres > var->yres_virtual) {
1535
    DPRINTK("virtual y resolution < physical y resolution not possible\n");
1536
    return -EINVAL;
1537
  }
1538
 
1539
  /* Banshee doesn't support interlace, but Voodoo4 and probably Voodoo3 do. */
1540
  if(((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
1541
     && (i->dev == PCI_DEVICE_ID_3DFX_BANSHEE)) {
1542
    DPRINTK("interlace not supported on Banshee\n");
1543
    return -EINVAL;
1544
  }
1545
 
1546
  memset(par, 0, sizeof(struct tdfxfb_par));
1547
 
1548
  switch(i->dev) {
1549
  case PCI_DEVICE_ID_3DFX_BANSHEE:
1550
  case PCI_DEVICE_ID_3DFX_VOODOO3:
1551
  case PCI_DEVICE_ID_3DFX_VOODOO5:
1552
    par->width       = (var->xres + 15) & ~15; /* could sometimes be 8 */
1553
    par->width_virt  = par->width;
1554
    par->height      = var->yres;
1555
    par->height_virt = var->yres_virtual;
1556
    par->bpp         = var->bits_per_pixel;
1557
    par->ppitch      = var->bits_per_pixel;
1558
    par->lpitch      = par->width* ((par->ppitch+7)>>3);
1559
    par->cmap_len    = (par->bpp == 8) ? 256 : 16;
1560
 
1561
    par->baseline = 0;
1562
 
1563
    if(par->width < 320 || par->width > 2048) {
1564
      DPRINTK("width not supported: %u\n", par->width);
1565
      return -EINVAL;
1566
    }
1567
    if(par->height < 200 || par->height > 2048) {
1568
      DPRINTK("height not supported: %u\n", par->height);
1569
      return -EINVAL;
1570
    }
1571
    if(par->lpitch*par->height_virt > i->bufbase_size) {
1572
      DPRINTK("no memory for screen (%ux%ux%u)\n",
1573
              par->width, par->height_virt, par->bpp);
1574
      return -EINVAL;
1575
    }
1576
    par->pixclock = PICOS2KHZ(var->pixclock);
1577
    if(par->pixclock > i->max_pixclock) {
1578
      DPRINTK("pixclock too high (%uKHz)\n", par->pixclock);
1579
      return -EINVAL;
1580
    }
1581
 
1582
    par->hdispend = var->xres;
1583
    par->hsyncsta = par->hdispend + var->right_margin;
1584
    par->hsyncend = par->hsyncsta + var->hsync_len;
1585
    par->htotal   = par->hsyncend + var->left_margin;
1586
 
1587
    par->vdispend = var->yres;
1588
    par->vsyncsta = par->vdispend + var->lower_margin;
1589
    par->vsyncend = par->vsyncsta + var->vsync_len;
1590
    par->vtotal   = par->vsyncend + var->upper_margin;
1591
 
1592
    if(var->sync & FB_SYNC_HOR_HIGH_ACT)
1593
      par->video |= TDFXF_HSYNC_ACT_HIGH;
1594
    else
1595
      par->video |= TDFXF_HSYNC_ACT_LOW;
1596
    if(var->sync & FB_SYNC_VERT_HIGH_ACT)
1597
      par->video |= TDFXF_VSYNC_ACT_HIGH;
1598
    else
1599
      par->video |= TDFXF_VSYNC_ACT_LOW;
1600
    if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1601
      par->video |= TDFXF_LINE_DOUBLE;
1602
    else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
1603
      par->video |= TDFXF_INTERLACE;
1604
    if(var->activate == FB_ACTIVATE_NOW)
1605
      par->video |= TDFXF_VIDEO_ENABLE;
1606
  }
1607
 
1608
  if(var->accel_flags & FB_ACCELF_TEXT)
1609
    par->accel_flags = FB_ACCELF_TEXT;
1610
  else
1611
    par->accel_flags = 0;
1612
 
1613
  return 0;
1614
}
1615
 
1616
static int tdfxfb_encode_var(struct fb_var_screeninfo* var,
1617
                            const struct tdfxfb_par* par,
1618
                            const struct fb_info_tdfx* info) {
1619
  struct fb_var_screeninfo v;
1620
 
1621
  memset(&v, 0, sizeof(struct fb_var_screeninfo));
1622
  v.xres_virtual   = par->width_virt;
1623
  v.yres_virtual   = par->height_virt;
1624
  v.xres           = par->width;
1625
  v.yres           = par->height;
1626
  v.right_margin   = par->hsyncsta - par->hdispend;
1627
  v.hsync_len      = par->hsyncend - par->hsyncsta;
1628
  v.left_margin    = par->htotal   - par->hsyncend;
1629
  v.lower_margin   = par->vsyncsta - par->vdispend;
1630
  v.vsync_len      = par->vsyncend - par->vsyncsta;
1631
  v.upper_margin   = par->vtotal   - par->vsyncend;
1632
  v.bits_per_pixel = par->bpp;
1633
  switch(par->bpp) {
1634
  case 8:
1635
    v.red.length = v.green.length = v.blue.length = 8;
1636
    break;
1637
  case 16:
1638
    v.red.offset   = 11;
1639
    v.red.length   = 5;
1640
    v.green.offset = 5;
1641
    v.green.length = 6;
1642
    v.blue.offset  = 0;
1643
    v.blue.length  = 5;
1644
    break;
1645
  case 24:
1646
  case 32:
1647
    v.red.offset   = 16;
1648
    v.green.offset = 8;
1649
    v.blue.offset  = 0;
1650
    v.red.length = v.green.length = v.blue.length = 8;
1651
    break;
1652
  }
1653
  v.height = v.width = -1;
1654
  v.pixclock = KHZ2PICOS(par->pixclock);
1655
  if((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
1656
    v.sync |= FB_SYNC_HOR_HIGH_ACT;
1657
  if((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
1658
    v.sync |= FB_SYNC_VERT_HIGH_ACT;
1659
  if(par->video & TDFXF_LINE_DOUBLE)
1660
    v.vmode = FB_VMODE_DOUBLE;
1661
  else if(par->video & TDFXF_INTERLACE)
1662
    v.vmode = FB_VMODE_INTERLACED;
1663
  *var = v;
1664
  return 0;
1665
}
1666
 
1667
static int tdfxfb_encode_fix(struct fb_fix_screeninfo*  fix,
1668
                             const struct tdfxfb_par*   par,
1669
                             const struct fb_info_tdfx* info) {
1670
  memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1671
 
1672
  switch(info->dev) {
1673
  case PCI_DEVICE_ID_3DFX_BANSHEE:
1674
    strcpy(fix->id, "3Dfx Banshee");
1675
    break;
1676
  case PCI_DEVICE_ID_3DFX_VOODOO3:
1677
    strcpy(fix->id, "3Dfx Voodoo3");
1678
    break;
1679
  case PCI_DEVICE_ID_3DFX_VOODOO5:
1680
    strcpy(fix->id, "3Dfx Voodoo5");
1681
    break;
1682
  default:
1683
    return -EINVAL;
1684
  }
1685
 
1686
  fix->smem_start  = info->bufbase_phys;
1687
  fix->smem_len    = info->bufbase_size;
1688
  fix->mmio_start  = info->regbase_phys;
1689
  fix->mmio_len    = info->regbase_size;
1690
  fix->accel       = FB_ACCEL_3DFX_BANSHEE;
1691
  fix->type        = FB_TYPE_PACKED_PIXELS;
1692
  fix->type_aux    = 0;
1693
  fix->line_length = par->lpitch;
1694
  fix->visual      = (par->bpp == 8)
1695
                     ? FB_VISUAL_PSEUDOCOLOR
1696
                     : FB_VISUAL_TRUECOLOR;
1697
 
1698
  fix->xpanstep    = 0;
1699
  fix->ypanstep    = nopan ? 0 : 1;
1700
  fix->ywrapstep   = nowrap ? 0 : 1;
1701
 
1702
  return 0;
1703
}
1704
 
1705
static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
1706
                          int con,
1707
                          struct fb_info *fb) {
1708
  const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1709
  struct tdfxfb_par par;
1710
 
1711
  if(con == -1)
1712
    par = info->default_par;
1713
  else
1714
    tdfxfb_decode_var(&fb_display[con].var, &par, info);
1715
  tdfxfb_encode_fix(fix, &par, info);
1716
  return 0;
1717
}
1718
 
1719
static int tdfxfb_get_var(struct fb_var_screeninfo *var,
1720
                          int con,
1721
                          struct fb_info *fb) {
1722
  const struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1723
 
1724
  if(con == -1)
1725
    tdfxfb_encode_var(var, &info->default_par, info);
1726
  else
1727
    *var = fb_display[con].var;
1728
  return 0;
1729
}
1730
 
1731
static void tdfxfb_set_dispsw(struct display *disp,
1732
                              struct fb_info_tdfx *info,
1733
                              int bpp,
1734
                              int accel) {
1735
 
1736
  if (disp->dispsw && disp->conp)
1737
     fb_con.con_cursor(disp->conp, CM_ERASE);
1738
  switch(bpp) {
1739
#ifdef FBCON_HAS_CFB8
1740
  case 8:
1741
    disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8;
1742
    if (nohwcursor) fbcon_banshee8.cursor = NULL;
1743
    break;
1744
#endif
1745
#ifdef FBCON_HAS_CFB16
1746
  case 16:
1747
    disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16;
1748
    disp->dispsw_data = info->fbcon_cmap.cfb16;
1749
    if (nohwcursor) fbcon_banshee16.cursor = NULL;
1750
    break;
1751
#endif
1752
#ifdef FBCON_HAS_CFB24
1753
  case 24:
1754
    disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24;
1755
    disp->dispsw_data = info->fbcon_cmap.cfb24;
1756
    if (nohwcursor) fbcon_banshee24.cursor = NULL;
1757
    break;
1758
#endif
1759
#ifdef FBCON_HAS_CFB32
1760
  case 32:
1761
    disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32;
1762
    disp->dispsw_data = info->fbcon_cmap.cfb32;
1763
    if (nohwcursor) fbcon_banshee32.cursor = NULL;
1764
    break;
1765
#endif
1766
  default:
1767
    disp->dispsw = &fbcon_dummy;
1768
  }
1769
 
1770
}
1771
 
1772
static int tdfxfb_set_var(struct fb_var_screeninfo *var,
1773
                          int con,
1774
                          struct fb_info *fb) {
1775
   struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
1776
   struct tdfxfb_par par;
1777
   struct display *display;
1778
   int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
1779
   int activate = var->activate;
1780
   int j,k;
1781
 
1782
   if(con >= 0)
1783
     display = &fb_display[con];
1784
   else
1785
     display = fb->disp;        /* used during initialization */
1786
 
1787
   if((err = tdfxfb_decode_var(var, &par, info)))
1788
     return err;
1789
 
1790
   tdfxfb_encode_var(var, &par, info);
1791
 
1792
   if((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
1793
      oldxres  = display->var.xres;
1794
      oldyres  = display->var.yres;
1795
      oldvxres = display->var.xres_virtual;
1796
      oldvyres = display->var.yres_virtual;
1797
      oldbpp   = display->var.bits_per_pixel;
1798
      oldaccel = display->var.accel_flags;
1799
      display->var = *var;
1800
      if(con < 0                         ||
1801
         oldxres  != var->xres           ||
1802
         oldyres  != var->yres           ||
1803
         oldvxres != var->xres_virtual   ||
1804
         oldvyres != var->yres_virtual   ||
1805
         oldbpp   != var->bits_per_pixel ||
1806
         oldaccel != var->accel_flags) {
1807
         struct fb_fix_screeninfo fix;
1808
 
1809
         tdfxfb_encode_fix(&fix, &par, info);
1810
         display->screen_base    = info->bufbase_virt;
1811
         display->visual         = fix.visual;
1812
         display->type           = fix.type;
1813
         display->type_aux       = fix.type_aux;
1814
         display->ypanstep       = fix.ypanstep;
1815
         display->ywrapstep      = fix.ywrapstep;
1816
         display->line_length    = fix.line_length;
1817
         display->next_line      = fix.line_length;
1818
         display->can_soft_blank = 1;
1819
         display->inverse        = inverse;
1820
         accel = var->accel_flags & FB_ACCELF_TEXT;
1821
         tdfxfb_set_dispsw(display, info, par.bpp, accel);
1822
 
1823
         if(nopan) display->scrollmode = SCROLL_YREDRAW;
1824
 
1825
         if (info->fb_info.changevar)
1826
           (*info->fb_info.changevar)(con);
1827
      }
1828
      if (var->bits_per_pixel==8)
1829
        for(j = 0; j < 16; j++) {
1830
           k = color_table[j];
1831
           fb_info.palette[j].red   = default_red[k];
1832
           fb_info.palette[j].green = default_grn[k];
1833
           fb_info.palette[j].blue  = default_blu[k];
1834
        }
1835
 
1836
      del_timer(&(info->cursor.timer));
1837
      fb_info.cursor.state=CM_ERASE;
1838
      if(!info->fb_info.display_fg ||
1839
         info->fb_info.display_fg->vc_num == con ||
1840
         con < 0)
1841
        tdfxfb_set_par(&par, info);
1842
      if (!nohwcursor)
1843
        if (display && display->conp)
1844
          tdfxfb_createcursor( display );
1845
      info->cursor.redraw=1;
1846
      if(oldbpp != var->bits_per_pixel || con < 0) {
1847
         if((err = fb_alloc_cmap(&display->cmap, 0, 0)))
1848
           return err;
1849
         tdfxfb_install_cmap(display, &(info->fb_info));
1850
      }
1851
   }
1852
 
1853
   return 0;
1854
}
1855
 
1856
static int tdfxfb_pan_display(struct fb_var_screeninfo* var,
1857
                              int con,
1858
                              struct fb_info* fb) {
1859
  struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
1860
 
1861
  if(nopan)                return -EINVAL;
1862
  if(var->xoffset)         return -EINVAL;
1863
  if(var->yoffset > var->yres_virtual)   return -EINVAL;
1864
  if(nowrap &&
1865
     (var->yoffset + var->yres > var->yres_virtual)) return -EINVAL;
1866
 
1867
  if (con==currcon)
1868
    do_pan_var(var,i);
1869
 
1870
  fb_display[con].var.xoffset=var->xoffset;
1871
  fb_display[con].var.yoffset=var->yoffset;
1872
  return 0;
1873
}
1874
 
1875
static int tdfxfb_get_cmap(struct fb_cmap *cmap,
1876
                           int kspc,
1877
                           int con,
1878
                           struct fb_info *fb) {
1879
 
1880
   struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
1881
   struct display *d=(con<0) ? fb->disp : fb_display + con;
1882
 
1883
   if(con == currcon) {
1884
      /* current console? */
1885
      return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
1886
   } else if(d->cmap.len) {
1887
      /* non default colormap? */
1888
      fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
1889
   } else {
1890
      fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len), cmap, kspc ? 0 : 2);
1891
   }
1892
   return 0;
1893
}
1894
 
1895
static int tdfxfb_set_cmap(struct fb_cmap *cmap,
1896
                           int kspc,
1897
                           int con,
1898
                           struct fb_info *fb) {
1899
   struct display *d=(con<0) ? fb->disp : fb_display + con;
1900
   struct fb_info_tdfx *i = (struct fb_info_tdfx*)fb;
1901
 
1902
   int cmap_len= (i->current_par.bpp == 8) ? 256 : 16;
1903
   if (d->cmap.len!=cmap_len) {
1904
      int err;
1905
      if((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
1906
        return err;
1907
   }
1908
   if(con == currcon) {
1909
      /* current console? */
1910
      return fb_set_cmap(cmap, kspc, tdfxfb_setcolreg, fb);
1911
   } else {
1912
      fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
1913
   }
1914
   return 0;
1915
}
1916
 
1917
/**
1918
 *      tdfxfb_probe - Device Initializiation
1919
 *
1920
 *      @pdev:  PCI Device to initialize
1921
 *      @id:    PCI Device ID
1922
 *
1923
 *      Initializes and allocates resources for PCI device @pdev.
1924
 *
1925
 */
1926
static int __devinit tdfxfb_probe(struct pci_dev *pdev,
1927
                                  const struct pci_device_id *id)
1928
{
1929
        struct fb_var_screeninfo var;
1930
        char *name = NULL;
1931
 
1932
        fb_info.dev = pdev->device;
1933
 
1934
        switch (pdev->device) {
1935
                case PCI_DEVICE_ID_3DFX_BANSHEE:
1936
                        fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK;
1937
                        name = "Banshee";
1938
                        break;
1939
                case PCI_DEVICE_ID_3DFX_VOODOO3:
1940
                        fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK;
1941
                        name = "Voodoo3";
1942
                        break;
1943
                case PCI_DEVICE_ID_3DFX_VOODOO5:
1944
                        fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK;
1945
                        name = "Voodoo5";
1946
                        break;
1947
        }
1948
 
1949
        if (pci_enable_device(pdev))
1950
        {
1951
                printk(KERN_WARNING "fb: Unable to enable %s PCI device.\n", name);
1952
                return -ENXIO;
1953
        }
1954
 
1955
        fb_info.regbase_phys = pci_resource_start(pdev, 0);
1956
        fb_info.regbase_size = 1 << 24;
1957
        fb_info.regbase_virt = ioremap_nocache(fb_info.regbase_phys, 1 << 24);
1958
 
1959
        if (!fb_info.regbase_virt) {
1960
                printk(KERN_WARNING "fb: Can't remap %s register area.\n", name);
1961
                return -ENXIO;
1962
        }
1963
 
1964
        fb_info.bufbase_phys = pci_resource_start (pdev, 1);
1965
 
1966
        if (!(fb_info.bufbase_size = do_lfb_size())) {
1967
                iounmap(fb_info.regbase_virt);
1968
                printk(KERN_WARNING "fb: Can't count %s memory.\n", name);
1969
                return -ENXIO;
1970
        }
1971
 
1972
        fb_info.bufbase_virt = ioremap_nocache(fb_info.bufbase_phys,
1973
                                               fb_info.bufbase_size);
1974
 
1975
        if (!fb_info.regbase_virt) {
1976
                printk(KERN_WARNING "fb: Can't remap %s framebuffer.\n", name);
1977
                iounmap(fb_info.regbase_virt);
1978
                return -ENXIO;
1979
        }
1980
 
1981
        fb_info.iobase = pci_resource_start (pdev, 2);
1982
 
1983
        if (!fb_info.iobase) {
1984
                printk(KERN_WARNING "fb: Can't access %s I/O ports.\n", name);
1985
                iounmap(fb_info.regbase_virt);
1986
                iounmap(fb_info.bufbase_virt);
1987
                return -ENXIO;
1988
        }
1989
 
1990
        printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
1991
 
1992
#ifdef CONFIG_MTRR
1993
        if (!nomtrr) {
1994
                fb_info.mtrr_idx = mtrr_add(fb_info.bufbase_phys,
1995
                                            fb_info.bufbase_size,
1996
                                            MTRR_TYPE_WRCOMB, 1);
1997
                printk(KERN_INFO "fb: MTRR's turned on\n");
1998
        }
1999
#endif
2000
 
2001
        /* clear framebuffer memory */
2002
        memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
2003
        currcon = -1;
2004
 
2005
        if (!nohwcursor)
2006
                tdfxfb_hwcursor_init();
2007
 
2008
        init_timer(&fb_info.cursor.timer);
2009
        fb_info.cursor.timer.function = do_flashcursor;
2010
        fb_info.cursor.timer.data = (unsigned long)(&fb_info);
2011
        fb_info.cursor.state = CM_ERASE;
2012
        spin_lock_init(&fb_info.DAClock);
2013
 
2014
        strcpy(fb_info.fb_info.modename, "3Dfx ");
2015
        strcat(fb_info.fb_info.modename, name);
2016
        fb_info.fb_info.changevar  = NULL;
2017
        fb_info.fb_info.node       = -1;
2018
        fb_info.fb_info.fbops      = &tdfxfb_ops;
2019
        fb_info.fb_info.disp       = &fb_info.disp;
2020
        strcpy(fb_info.fb_info.fontname, fontname);
2021
        fb_info.fb_info.switch_con = &tdfxfb_switch_con;
2022
        fb_info.fb_info.updatevar  = &tdfxfb_updatevar;
2023
        fb_info.fb_info.blank      = &tdfxfb_blank;
2024
        fb_info.fb_info.flags      = FBINFO_FLAG_DEFAULT;
2025
 
2026
        memset(&var, 0, sizeof(var));
2027
 
2028
        if (!mode_option || !fb_find_mode(&var, &fb_info.fb_info,
2029
                                          mode_option, NULL, 0, NULL, 8))
2030
                var = default_mode[0].var;
2031
 
2032
        noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
2033
                  (var.accel_flags |=  FB_ACCELF_TEXT) ;
2034
 
2035
        if (tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
2036
                /*
2037
                 * ugh -- can't use the mode from the mode db. (or command
2038
                 * line), so try the default
2039
                 */
2040
 
2041
                printk(KERN_NOTICE "tdfxfb: can't decode the supplied video mode, using default\n");
2042
 
2043
                var = default_mode[0].var;
2044
 
2045
                noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
2046
                          (var.accel_flags |=  FB_ACCELF_TEXT) ;
2047
 
2048
                if (tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
2049
                        /* this is getting really bad!... */
2050
                        printk(KERN_WARNING "tdfxfb: can't decode default video mode\n");
2051
                        return -ENXIO;
2052
                }
2053
        }
2054
 
2055
        fb_info.disp.screen_base = fb_info.bufbase_virt;
2056
        fb_info.disp.var         = var;
2057
 
2058
        if (tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
2059
                printk(KERN_WARNING "tdfxfb: can't set default video mode\n");
2060
                return -ENXIO;
2061
        }
2062
 
2063
        if (register_framebuffer(&fb_info.fb_info) < 0) {
2064
                printk(KERN_WARNING "tdfxfb: can't register framebuffer\n");
2065
                return -ENXIO;
2066
        }
2067
 
2068
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
2069
             GET_FB_IDX(fb_info.fb_info.node), fb_info.fb_info.modename);
2070
 
2071
        return 0;
2072
}
2073
 
2074
/**
2075
 *      tdfxfb_remove - Device removal
2076
 *
2077
 *      @pdev:  PCI Device to cleanup
2078
 *
2079
 *      Releases all resources allocated during the course of the driver's
2080
 *      lifetime for the PCI device @pdev.
2081
 *
2082
 */
2083
static void __devexit tdfxfb_remove(struct pci_dev *pdev)
2084
{
2085
        unregister_framebuffer(&fb_info.fb_info);
2086
        del_timer_sync(&fb_info.cursor.timer);
2087
 
2088
#ifdef CONFIG_MTRR
2089
       if (!nomtrr) {
2090
          mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys, fb_info.bufbase_size);
2091
            printk("fb: MTRR's turned off\n");
2092
       }
2093
#endif
2094
 
2095
        iounmap(fb_info.regbase_virt);
2096
        iounmap(fb_info.bufbase_virt);
2097
}
2098
 
2099
int __init tdfxfb_init(void)
2100
{
2101
        return pci_module_init(&tdfxfb_driver);
2102
}
2103
 
2104
static void __exit tdfxfb_exit(void)
2105
{
2106
        pci_unregister_driver(&tdfxfb_driver);
2107
}
2108
 
2109
MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
2110
MODULE_DESCRIPTION("3Dfx framebuffer device driver");
2111
MODULE_LICENSE("GPL");
2112
 
2113
 
2114
#ifdef MODULE
2115
module_init(tdfxfb_init);
2116
#endif
2117
module_exit(tdfxfb_exit);
2118
 
2119
 
2120
#ifndef MODULE
2121
void tdfxfb_setup(char *options,
2122
                  int *ints) {
2123
  char* this_opt;
2124
 
2125
  if(!options || !*options)
2126
    return;
2127
 
2128
  while((this_opt = strsep(&options, ",")) != NULL) {
2129
    if(!*this_opt)
2130
      continue;
2131
    if(!strcmp(this_opt, "inverse")) {
2132
      inverse = 1;
2133
      fb_invert_cmaps();
2134
    } else if(!strcmp(this_opt, "noaccel")) {
2135
      noaccel = nopan = nowrap = nohwcursor = 1;
2136
    } else if(!strcmp(this_opt, "nopan")) {
2137
      nopan = 1;
2138
    } else if(!strcmp(this_opt, "nowrap")) {
2139
      nowrap = 1;
2140
    } else if (!strcmp(this_opt, "nohwcursor")) {
2141
      nohwcursor = 1;
2142
#ifdef CONFIG_MTRR
2143
    } else if (!strcmp(this_opt, "nomtrr")) {
2144
      nomtrr = 1;
2145
#endif
2146
    } else if (!strncmp(this_opt, "font:", 5)) {
2147
      strncpy(fontname, this_opt + 5, 40);
2148
    } else {
2149
      mode_option = this_opt;
2150
    }
2151
  }
2152
}
2153
#endif
2154
 
2155
static int tdfxfb_switch_con(int con,
2156
                             struct fb_info *fb) {
2157
   struct fb_info_tdfx *info = (struct fb_info_tdfx*)fb;
2158
   struct tdfxfb_par par;
2159
   int old_con = currcon;
2160
   int set_par = 1;
2161
 
2162
   /* Do we have to save the colormap? */
2163
   if (currcon>=0)
2164
     if(fb_display[currcon].cmap.len)
2165
       fb_get_cmap(&fb_display[currcon].cmap, 1, tdfxfb_getcolreg, fb);
2166
 
2167
   currcon = con;
2168
   fb_display[currcon].var.activate = FB_ACTIVATE_NOW;
2169
   tdfxfb_decode_var(&fb_display[con].var, &par, info);
2170
   if (old_con>=0 && vt_cons[old_con]->vc_mode!=KD_GRAPHICS) {
2171
     /* check if we have to change video registers */
2172
     struct tdfxfb_par old_par;
2173
     tdfxfb_decode_var(&fb_display[old_con].var, &old_par, info);
2174
     if (!memcmp(&par,&old_par,sizeof(par)))
2175
        set_par = 0;     /* avoid flicker */
2176
   }
2177
   if (set_par)
2178
     tdfxfb_set_par(&par, info);
2179
 
2180
   if (fb_display[con].dispsw && fb_display[con].conp)
2181
     fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
2182
 
2183
   del_timer(&(info->cursor.timer));
2184
   fb_info.cursor.state=CM_ERASE;
2185
 
2186
   if (!nohwcursor)
2187
     if (fb_display[con].conp)
2188
       tdfxfb_createcursor( &fb_display[con] );
2189
 
2190
   info->cursor.redraw=1;
2191
 
2192
   tdfxfb_set_dispsw(&fb_display[con],
2193
                     info,
2194
                     par.bpp,
2195
                     par.accel_flags & FB_ACCELF_TEXT);
2196
 
2197
   tdfxfb_install_cmap(&fb_display[con], fb);
2198
   tdfxfb_updatevar(con, fb);
2199
 
2200
   return 1;
2201
}
2202
 
2203
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
2204
static void tdfxfb_blank(int blank,
2205
                         struct fb_info *fb) {
2206
  u32 dacmode, state = 0, vgablank = 0;
2207
 
2208
  dacmode = tdfx_inl(DACMODE);
2209
 
2210
  switch(blank) {
2211
  case 0: /* Screen: On; HSync: On, VSync: On */
2212
    state    = 0;
2213
    vgablank = 0;
2214
    break;
2215
  case 1: /* Screen: Off; HSync: On, VSync: On */
2216
    state    = 0;
2217
    vgablank = 1;
2218
    break;
2219
  case 2: /* Screen: Off; HSync: On, VSync: Off */
2220
    state    = BIT(3);
2221
    vgablank = 1;
2222
    break;
2223
  case 3: /* Screen: Off; HSync: Off, VSync: On */
2224
    state    = BIT(1);
2225
    vgablank = 1;
2226
    break;
2227
  case 4: /* Screen: Off; HSync: Off, VSync: Off */
2228
    state    = BIT(1) | BIT(3);
2229
    vgablank = 1;
2230
    break;
2231
  }
2232
 
2233
  dacmode &= ~(BIT(1) | BIT(3));
2234
  dacmode |= state;
2235
  banshee_make_room(1);
2236
  tdfx_outl(DACMODE, dacmode);
2237
  if(vgablank)
2238
    vga_disable_video();
2239
  else
2240
    vga_enable_video();
2241
 
2242
  return;
2243
}
2244
 
2245
static int  tdfxfb_updatevar(int con,
2246
                             struct fb_info* fb) {
2247
 
2248
   struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
2249
   if ((con==currcon) && (!nopan))
2250
     do_pan_var(&fb_display[con].var,i);
2251
   return 0;
2252
}
2253
 
2254
static int tdfxfb_getcolreg(unsigned        regno,
2255
                            unsigned*       red,
2256
                            unsigned*       green,
2257
                            unsigned*       blue,
2258
                            unsigned*       transp,
2259
                            struct fb_info* fb) {
2260
   struct fb_info_tdfx* i = (struct fb_info_tdfx*)fb;
2261
 
2262
   if (regno > i->current_par.cmap_len) return 1;
2263
 
2264
   *red    = i->palette[regno].red;
2265
   *green  = i->palette[regno].green;
2266
   *blue   = i->palette[regno].blue;
2267
   *transp = 0;
2268
 
2269
   return 0;
2270
}
2271
 
2272
static int tdfxfb_setcolreg(unsigned        regno,
2273
                            unsigned        red,
2274
                            unsigned        green,
2275
                            unsigned        blue,
2276
                            unsigned        transp,
2277
                            struct fb_info* info) {
2278
   struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
2279
#ifdef FBCON_HAS_CFB8   
2280
   u32 rgbcol;
2281
#endif
2282
   if (regno >= i->current_par.cmap_len) return 1;
2283
 
2284
   i->palette[regno].red    = red;
2285
   i->palette[regno].green  = green;
2286
   i->palette[regno].blue   = blue;
2287
 
2288
   switch(i->current_par.bpp) {
2289
#ifdef FBCON_HAS_CFB8
2290
    case 8:
2291
      rgbcol=(((u32)red   & 0xff00) << 8) |
2292
        (((u32)green & 0xff00) << 0) |
2293
        (((u32)blue  & 0xff00) >> 8);
2294
      do_setpalentry(regno,rgbcol);
2295
      break;
2296
#endif
2297
#ifdef FBCON_HAS_CFB16
2298
    case 16:
2299
      i->fbcon_cmap.cfb16[regno] =
2300
        (((u32)red   & 0xf800) >> 0) |
2301
        (((u32)green & 0xfc00) >> 5) |
2302
        (((u32)blue  & 0xf800) >> 11);
2303
         break;
2304
#endif
2305
#ifdef FBCON_HAS_CFB24
2306
    case 24:
2307
      i->fbcon_cmap.cfb24[regno] =
2308
        (((u32)red & 0xff00) << 8) |
2309
        (((u32)green & 0xff00) << 0) |
2310
        (((u32)blue & 0xff00) >> 8);
2311
      break;
2312
#endif
2313
#ifdef FBCON_HAS_CFB32
2314
    case 32:
2315
      i->fbcon_cmap.cfb32[regno] =
2316
        (((u32)red   & 0xff00) << 8) |
2317
        (((u32)green & 0xff00) << 0) |
2318
        (((u32)blue  & 0xff00) >> 8);
2319
      break;
2320
#endif
2321
    default:
2322
      DPRINTK("bad depth %u\n", i->current_par.bpp);
2323
      break;
2324
   }
2325
   return 0;
2326
}
2327
 
2328
static void tdfxfb_install_cmap(struct display *d,struct fb_info *info)
2329
{
2330
   struct fb_info_tdfx* i = (struct fb_info_tdfx*)info;
2331
 
2332
   if(d->cmap.len) {
2333
      fb_set_cmap(&(d->cmap), 1, tdfxfb_setcolreg, info);
2334
   } else {
2335
      fb_set_cmap(fb_default_cmap(i->current_par.cmap_len), 1,
2336
                  tdfxfb_setcolreg, info);
2337
   }
2338
}
2339
 
2340
static void tdfxfb_createcursorshape(struct display* p)
2341
{
2342
   unsigned int h,cu,cd;
2343
 
2344
   h=fontheight(p);
2345
   cd=h;
2346
   if (cd >= 10) cd --;
2347
   fb_info.cursor.type=p->conp->vc_cursor_type & CUR_HWMASK;
2348
   switch (fb_info.cursor.type) {
2349
      case CUR_NONE:
2350
        cu=cd;
2351
        break;
2352
      case CUR_UNDERLINE:
2353
        cu=cd - 2;
2354
        break;
2355
      case CUR_LOWER_THIRD:
2356
        cu=(h * 2) / 3;
2357
        break;
2358
      case CUR_LOWER_HALF:
2359
        cu=h / 2;
2360
        break;
2361
      case CUR_TWO_THIRDS:
2362
        cu=h / 3;
2363
        break;
2364
      case CUR_BLOCK:
2365
      default:
2366
        cu=0;
2367
        cd = h;
2368
        break;
2369
   }
2370
   fb_info.cursor.w=fontwidth(p);
2371
   fb_info.cursor.u=cu;
2372
   fb_info.cursor.d=cd;
2373
}
2374
 
2375
static void tdfxfb_createcursor(struct display *p)
2376
{
2377
   u8 *cursorbase;
2378
   u32 xline;
2379
   unsigned int i;
2380
   unsigned int h,to;
2381
 
2382
   tdfxfb_createcursorshape(p);
2383
   xline = (~0) << (32 - fb_info.cursor.w);
2384
 
2385
#ifdef __LITTLE_ENDIAN
2386
   xline = swab32(xline);
2387
#else
2388
   switch (p->var.bits_per_pixel) {
2389
      case 8:
2390
      case 24:
2391
         xline = swab32(xline);
2392
         break;
2393
      case 16:
2394
         xline = ((xline & 0xff000000 ) >> 16 )
2395
               | ((xline & 0x00ff0000 ) >> 16 )
2396
               | ((xline & 0x0000ff00 ) << 16 )
2397
               | ((xline & 0x000000ff ) << 16 );
2398
         break;
2399
      case 32:
2400
         break;
2401
   }
2402
#endif
2403
 
2404
   cursorbase=(u8*)fb_info.bufbase_virt;
2405
   h=fb_info.cursor.cursorimage;
2406
 
2407
   to=fb_info.cursor.u;
2408
   for (i = 0; i < to; i++) {
2409
        writel(0, cursorbase+h);
2410
        writel(0, cursorbase+h+4);
2411
        writel(~0, cursorbase+h+8);
2412
        writel(~0, cursorbase+h+12);
2413
        h += 16;
2414
   }
2415
 
2416
   to = fb_info.cursor.d;
2417
 
2418
   for (; i < to; i++) {
2419
        writel(xline, cursorbase+h);
2420
        writel(0, cursorbase+h+4);
2421
        writel(~0, cursorbase+h+8);
2422
        writel(~0, cursorbase+h+12);
2423
        h += 16;
2424
   }
2425
 
2426
   for (; i < 64; i++) {
2427
        writel(0, cursorbase+h);
2428
        writel(0, cursorbase+h+4);
2429
        writel(~0, cursorbase+h+8);
2430
        writel(~0, cursorbase+h+12);
2431
        h += 16;
2432
   }
2433
}
2434
 
2435
static void tdfxfb_hwcursor_init(void)
2436
{
2437
   unsigned int start;
2438
   start = (fb_info.bufbase_size-1024) & (PAGE_MASK << 1);
2439
        /* even page boundary - on Voodoo4 4500 bottom 48 lines
2440
         * contained trash when just page boundary was used... */
2441
   fb_info.bufbase_size=start;
2442
   fb_info.cursor.cursorimage=fb_info.bufbase_size;
2443
   printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
2444
          fb_info.regbase_virt+fb_info.cursor.cursorimage);
2445
}
2446
 
2447
 

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.