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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [pm2fb.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Permedia2 framebuffer driver.
3
 *
4
 * 2.5/2.6 driver:
5
 * Copyright (c) 2003 Jim Hague (jim.hague@acm.org)
6
 *
7
 * based on 2.4 driver:
8
 * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
9
 * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
10
 *
11
 * and additional input from James Simmon's port of Hannu Mallat's tdfx
12
 * driver.
13
 *
14
 * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
15
 * have no access to other pm2fb implementations. Sparc (and thus
16
 * hopefully other big-endian) devices now work, thanks to a lot of
17
 * testing work by Ron Murray. I have no access to CVision hardware,
18
 * and therefore for now I am omitting the CVision code.
19
 *
20
 * Multiple boards support has been on the TODO list for ages.
21
 * Don't expect this to change.
22
 *
23
 * This file is subject to the terms and conditions of the GNU General Public
24
 * License. See the file COPYING in the main directory of this archive for
25
 * more details.
26
 *
27
 *
28
 */
29
 
30
#include <linux/module.h>
31
#include <linux/moduleparam.h>
32
#include <linux/kernel.h>
33
#include <linux/errno.h>
34
#include <linux/string.h>
35
#include <linux/mm.h>
36
#include <linux/slab.h>
37
#include <linux/delay.h>
38
#include <linux/fb.h>
39
#include <linux/init.h>
40
#include <linux/pci.h>
41
#ifdef CONFIG_MTRR
42
#include <asm/mtrr.h>
43
#endif
44
 
45
#include <video/permedia2.h>
46
#include <video/cvisionppc.h>
47
 
48
#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
49
#error  "The endianness of the target host has not been defined."
50
#endif
51
 
52
#if !defined(CONFIG_PCI)
53
#error "Only generic PCI cards supported."
54
#endif
55
 
56
#undef PM2FB_MASTER_DEBUG
57
#ifdef PM2FB_MASTER_DEBUG
58
#define DPRINTK(a, b...)        \
59
        printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
60
#else
61
#define DPRINTK(a, b...)
62
#endif
63
 
64
#define PM2_PIXMAP_SIZE (1600 * 4)
65
 
66
/*
67
 * Driver data
68
 */
69
static int hwcursor = 1;
70
static char *mode __devinitdata;
71
 
72
/*
73
 * The XFree GLINT driver will (I think to implement hardware cursor
74
 * support on TVP4010 and similar where there is no RAMDAC - see
75
 * comment in set_video) always request +ve sync regardless of what
76
 * the mode requires. This screws me because I have a Sun
77
 * fixed-frequency monitor which absolutely has to have -ve sync. So
78
 * these flags allow the user to specify that requests for +ve sync
79
 * should be silently turned in -ve sync.
80
 */
81
static int lowhsync;
82
static int lowvsync;
83
static int noaccel __devinitdata;
84
/* mtrr option */
85
#ifdef CONFIG_MTRR
86
static int nomtrr __devinitdata;
87
#endif
88
 
89
/*
90
 * The hardware state of the graphics card that isn't part of the
91
 * screeninfo.
92
 */
93
struct pm2fb_par
94
{
95
        pm2type_t       type;           /* Board type */
96
        unsigned char   __iomem *v_regs;/* virtual address of p_regs */
97
        u32             memclock;       /* memclock */
98
        u32             video;          /* video flags before blanking */
99
        u32             mem_config;     /* MemConfig reg at probe */
100
        u32             mem_control;    /* MemControl reg at probe */
101
        u32             boot_address;   /* BootAddress reg at probe */
102
        u32             palette[16];
103
        int             mtrr_handle;
104
};
105
 
106
/*
107
 * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
108
 * if we don't use modedb.
109
 */
110
static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
111
        .id =           "",
112
        .type =         FB_TYPE_PACKED_PIXELS,
113
        .visual =       FB_VISUAL_PSEUDOCOLOR,
114
        .xpanstep =     1,
115
        .ypanstep =     1,
116
        .ywrapstep =    0,
117
        .accel =        FB_ACCEL_3DLABS_PERMEDIA2,
118
};
119
 
120
/*
121
 * Default video mode. In case the modedb doesn't work.
122
 */
123
static struct fb_var_screeninfo pm2fb_var __devinitdata = {
124
        /* "640x480, 8 bpp @ 60 Hz */
125
        .xres =                 640,
126
        .yres =                 480,
127
        .xres_virtual =         640,
128
        .yres_virtual =         480,
129
        .bits_per_pixel =       8,
130
        .red =                  {0, 8, 0},
131
        .blue =                 {0, 8, 0},
132
        .green =                {0, 8, 0},
133
        .activate =             FB_ACTIVATE_NOW,
134
        .height =               -1,
135
        .width =                -1,
136
        .accel_flags =          0,
137
        .pixclock =             39721,
138
        .left_margin =          40,
139
        .right_margin =         24,
140
        .upper_margin =         32,
141
        .lower_margin =         11,
142
        .hsync_len =            96,
143
        .vsync_len =            2,
144
        .vmode =                FB_VMODE_NONINTERLACED
145
};
146
 
147
/*
148
 * Utility functions
149
 */
150
 
151
static inline u32 pm2_RD(struct pm2fb_par *p, s32 off)
152
{
153
        return fb_readl(p->v_regs + off);
154
}
155
 
156
static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v)
157
{
158
        fb_writel(v, p->v_regs + off);
159
}
160
 
161
static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx)
162
{
163
        pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
164
        mb();
165
        return pm2_RD(p, PM2R_RD_INDEXED_DATA);
166
}
167
 
168
static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx)
169
{
170
        pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
171
        mb();
172
        return pm2_RD(p,  PM2VR_RD_INDEXED_DATA);
173
}
174
 
175
static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
176
{
177
        pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
178
        wmb();
179
        pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
180
        wmb();
181
}
182
 
183
static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
184
{
185
        pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
186
        wmb();
187
        pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
188
        wmb();
189
}
190
 
191
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
192
#define WAIT_FIFO(p, a)
193
#else
194
static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
195
{
196
        while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
197
                cpu_relax();
198
}
199
#endif
200
 
201
/*
202
 * partial products for the supported horizontal resolutions.
203
 */
204
#define PACKPP(p0, p1, p2)      (((p2) << 6) | ((p1) << 3) | (p0))
205
static const struct {
206
        u16 width;
207
        u16 pp;
208
} pp_table[] = {
209
        { 32,   PACKPP(1, 0, 0) }, { 64,  PACKPP(1, 1, 0) },
210
        { 96,   PACKPP(1, 1, 1) }, { 128,       PACKPP(2, 1, 1) },
211
        { 160,  PACKPP(2, 2, 1) }, { 192,       PACKPP(2, 2, 2) },
212
        { 224,  PACKPP(3, 2, 1) }, { 256,       PACKPP(3, 2, 2) },
213
        { 288,  PACKPP(3, 3, 1) }, { 320,       PACKPP(3, 3, 2) },
214
        { 384,  PACKPP(3, 3, 3) }, { 416,       PACKPP(4, 3, 1) },
215
        { 448,  PACKPP(4, 3, 2) }, { 512,       PACKPP(4, 3, 3) },
216
        { 544,  PACKPP(4, 4, 1) }, { 576,       PACKPP(4, 4, 2) },
217
        { 640,  PACKPP(4, 4, 3) }, { 768,       PACKPP(4, 4, 4) },
218
        { 800,  PACKPP(5, 4, 1) }, { 832,       PACKPP(5, 4, 2) },
219
        { 896,  PACKPP(5, 4, 3) }, { 1024,      PACKPP(5, 4, 4) },
220
        { 1056, PACKPP(5, 5, 1) }, { 1088,      PACKPP(5, 5, 2) },
221
        { 1152, PACKPP(5, 5, 3) }, { 1280,      PACKPP(5, 5, 4) },
222
        { 1536, PACKPP(5, 5, 5) }, { 1568,      PACKPP(6, 5, 1) },
223
        { 1600, PACKPP(6, 5, 2) }, { 1664,      PACKPP(6, 5, 3) },
224
        { 1792, PACKPP(6, 5, 4) }, { 2048,      PACKPP(6, 5, 5) },
225
        { 0,     0 } };
226
 
227
static u32 partprod(u32 xres)
228
{
229
        int i;
230
 
231
        for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
232
                ;
233
        if (pp_table[i].width == 0)
234
                DPRINTK("invalid width %u\n", xres);
235
        return pp_table[i].pp;
236
}
237
 
238
static u32 to3264(u32 timing, int bpp, int is64)
239
{
240
        switch (bpp) {
241
        case 24:
242
                timing *= 3;
243
        case 8:
244
                timing >>= 1;
245
        case 16:
246
                timing >>= 1;
247
        case 32:
248
                break;
249
        }
250
        if (is64)
251
                timing >>= 1;
252
        return timing;
253
}
254
 
255
static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
256
                    unsigned char *pp)
257
{
258
        unsigned char m;
259
        unsigned char n;
260
        unsigned char p;
261
        u32 f;
262
        s32 curr;
263
        s32 delta = 100000;
264
 
265
        *mm = *nn = *pp = 0;
266
        for (n = 2; n < 15; n++) {
267
                for (m = 2; m; m++) {
268
                        f = PM2_REFERENCE_CLOCK * m / n;
269
                        if (f >= 150000 && f <= 300000) {
270
                                for (p = 0; p < 5; p++, f >>= 1) {
271
                                        curr = (clk > f) ? clk - f : f - clk;
272
                                        if (curr < delta) {
273
                                                delta = curr;
274
                                                *mm = m;
275
                                                *nn = n;
276
                                                *pp = p;
277
                                        }
278
                                }
279
                        }
280
                }
281
        }
282
}
283
 
284
static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
285
                     unsigned char *pp)
286
{
287
        unsigned char m;
288
        unsigned char n;
289
        unsigned char p;
290
        u32 f;
291
        s32 delta = 1000;
292
 
293
        *mm = *nn = *pp = 0;
294
        for (m = 1; m < 128; m++) {
295
                for (n = 2 * m + 1; n; n++) {
296
                        for (p = 0; p < 2; p++) {
297
                                f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m;
298
                                if (clk > f - delta && clk < f + delta) {
299
                                        delta = (clk > f) ? clk - f : f - clk;
300
                                        *mm = m;
301
                                        *nn = n;
302
                                        *pp = p;
303
                                }
304
                        }
305
                }
306
        }
307
}
308
 
309
static void clear_palette(struct pm2fb_par *p)
310
{
311
        int i = 256;
312
 
313
        WAIT_FIFO(p, 1);
314
        pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
315
        wmb();
316
        while (i--) {
317
                WAIT_FIFO(p, 3);
318
                pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
319
                pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
320
                pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
321
        }
322
}
323
 
324
static void reset_card(struct pm2fb_par *p)
325
{
326
        if (p->type == PM2_TYPE_PERMEDIA2V)
327
                pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
328
        pm2_WR(p, PM2R_RESET_STATUS, 0);
329
        mb();
330
        while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
331
                cpu_relax();
332
        mb();
333
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
334
        DPRINTK("FIFO disconnect enabled\n");
335
        pm2_WR(p, PM2R_FIFO_DISCON, 1);
336
        mb();
337
#endif
338
 
339
        /* Restore stashed memory config information from probe */
340
        WAIT_FIFO(p, 3);
341
        pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control);
342
        pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address);
343
        wmb();
344
        pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config);
345
}
346
 
347
static void reset_config(struct pm2fb_par *p)
348
{
349
        WAIT_FIFO(p, 53);
350
        pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) &
351
                        ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED));
352
        pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
353
        pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
354
        pm2_WR(p, PM2R_FIFO_CONTROL, 0);
355
        pm2_WR(p, PM2R_APERTURE_ONE, 0);
356
        pm2_WR(p, PM2R_APERTURE_TWO, 0);
357
        pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
358
        pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
359
        pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
360
        pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
361
        pm2_WR(p, PM2R_LB_READ_MODE, 0);
362
        pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
363
        pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
364
        pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
365
        pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
366
        pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
367
        pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
368
        pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
369
        pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
370
        pm2_WR(p, PM2R_DITHER_MODE, 0);
371
        pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
372
        pm2_WR(p, PM2R_DEPTH_MODE, 0);
373
        pm2_WR(p, PM2R_STENCIL_MODE, 0);
374
        pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
375
        pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
376
        pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
377
        pm2_WR(p, PM2R_YUV_MODE, 0);
378
        pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
379
        pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
380
        pm2_WR(p, PM2R_FOG_MODE, 0);
381
        pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
382
        pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
383
        pm2_WR(p, PM2R_STATISTICS_MODE, 0);
384
        pm2_WR(p, PM2R_SCISSOR_MODE, 0);
385
        pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
386
        pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff);
387
        switch (p->type) {
388
        case PM2_TYPE_PERMEDIA2:
389
                pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
390
                pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
391
                pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
392
                pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
393
                pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
394
                pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
395
                pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
396
                pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
397
                break;
398
        case PM2_TYPE_PERMEDIA2V:
399
                pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
400
                break;
401
        }
402
}
403
 
404
static void set_aperture(struct pm2fb_par *p, u32 depth)
405
{
406
        /*
407
         * The hardware is little-endian. When used in big-endian
408
         * hosts, the on-chip aperture settings are used where
409
         * possible to translate from host to card byte order.
410
         */
411
        WAIT_FIFO(p, 2);
412
#ifdef __LITTLE_ENDIAN
413
        pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
414
#else
415
        switch (depth) {
416
        case 24:        /* RGB->BGR */
417
                /*
418
                 * We can't use the aperture to translate host to
419
                 * card byte order here, so we switch to BGR mode
420
                 * in pm2fb_set_par().
421
                 */
422
        case 8:         /* B->B */
423
                pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
424
                break;
425
        case 16:        /* HL->LH */
426
                pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP);
427
                break;
428
        case 32:        /* RGBA->ABGR */
429
                pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP);
430
                break;
431
        }
432
#endif
433
 
434
        /* We don't use aperture two, so this may be superflous */
435
        pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD);
436
}
437
 
438
static void set_color(struct pm2fb_par *p, unsigned char regno,
439
                      unsigned char r, unsigned char g, unsigned char b)
440
{
441
        WAIT_FIFO(p, 4);
442
        pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
443
        wmb();
444
        pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
445
        wmb();
446
        pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
447
        wmb();
448
        pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
449
}
450
 
451
static void set_memclock(struct pm2fb_par *par, u32 clk)
452
{
453
        int i;
454
        unsigned char m, n, p;
455
 
456
        switch (par->type) {
457
        case PM2_TYPE_PERMEDIA2V:
458
                pm2v_mnp(clk/2, &m, &n, &p);
459
                WAIT_FIFO(par, 12);
460
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
461
                pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
462
                pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
463
                pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n);
464
                pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
465
                pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
466
                rmb();
467
                for (i = 256; i; i--)
468
                        if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2)
469
                                break;
470
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
471
                break;
472
        case PM2_TYPE_PERMEDIA2:
473
                pm2_mnp(clk, &m, &n, &p);
474
                WAIT_FIFO(par, 10);
475
                pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
476
                pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
477
                pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
478
                pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
479
                pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
480
                rmb();
481
                for (i = 256; i; i--)
482
                        if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
483
                                break;
484
                break;
485
        }
486
}
487
 
488
static void set_pixclock(struct pm2fb_par *par, u32 clk)
489
{
490
        int i;
491
        unsigned char m, n, p;
492
 
493
        switch (par->type) {
494
        case PM2_TYPE_PERMEDIA2:
495
                pm2_mnp(clk, &m, &n, &p);
496
                WAIT_FIFO(par, 10);
497
                pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
498
                pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
499
                pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
500
                pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
501
                pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
502
                rmb();
503
                for (i = 256; i; i--)
504
                        if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
505
                                break;
506
                break;
507
        case PM2_TYPE_PERMEDIA2V:
508
                pm2v_mnp(clk/2, &m, &n, &p);
509
                WAIT_FIFO(par, 8);
510
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
511
                pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m);
512
                pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n);
513
                pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p);
514
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
515
                break;
516
        }
517
}
518
 
519
static void set_video(struct pm2fb_par *p, u32 video)
520
{
521
        u32 tmp;
522
        u32 vsync = video;
523
 
524
        DPRINTK("video = 0x%x\n", video);
525
 
526
        /*
527
         * The hardware cursor needs +vsync to recognise vert retrace.
528
         * We may not be using the hardware cursor, but the X Glint
529
         * driver may well. So always set +hsync/+vsync and then set
530
         * the RAMDAC to invert the sync if necessary.
531
         */
532
        vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK);
533
        vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH;
534
 
535
        WAIT_FIFO(p, 3);
536
        pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
537
 
538
        switch (p->type) {
539
        case PM2_TYPE_PERMEDIA2:
540
                tmp = PM2F_RD_PALETTE_WIDTH_8;
541
                if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
542
                        tmp |= 4; /* invert hsync */
543
                if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
544
                        tmp |= 8; /* invert vsync */
545
                pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp);
546
                break;
547
        case PM2_TYPE_PERMEDIA2V:
548
                tmp = 0;
549
                if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
550
                        tmp |= 1; /* invert hsync */
551
                if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
552
                        tmp |= 4; /* invert vsync */
553
                pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
554
                break;
555
        }
556
}
557
 
558
/*
559
 *      pm2fb_check_var - Optional function. Validates a var passed in.
560
 *      @var: frame buffer variable screen structure
561
 *      @info: frame buffer structure that represents a single frame buffer
562
 *
563
 *      Checks to see if the hardware supports the state requested by
564
 *      var passed in.
565
 *
566
 *      Returns negative errno on error, or zero on success.
567
 */
568
static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
569
{
570
        u32 lpitch;
571
 
572
        if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
573
            var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
574
                DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
575
                return -EINVAL;
576
        }
577
 
578
        if (var->xres != var->xres_virtual) {
579
                DPRINTK("virtual x resolution != "
580
                        "physical x resolution not supported\n");
581
                return -EINVAL;
582
        }
583
 
584
        if (var->yres > var->yres_virtual) {
585
                DPRINTK("virtual y resolution < "
586
                        "physical y resolution not possible\n");
587
                return -EINVAL;
588
        }
589
 
590
        /* permedia cannot blit over 2048 */
591
        if (var->yres_virtual > 2047) {
592
                var->yres_virtual = 2047;
593
        }
594
 
595
        if (var->xoffset) {
596
                DPRINTK("xoffset not supported\n");
597
                return -EINVAL;
598
        }
599
 
600
        if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
601
                DPRINTK("interlace not supported\n");
602
                return -EINVAL;
603
        }
604
 
605
        var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
606
        lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
607
 
608
        if (var->xres < 320 || var->xres > 1600) {
609
                DPRINTK("width not supported: %u\n", var->xres);
610
                return -EINVAL;
611
        }
612
 
613
        if (var->yres < 200 || var->yres > 1200) {
614
                DPRINTK("height not supported: %u\n", var->yres);
615
                return -EINVAL;
616
        }
617
 
618
        if (lpitch * var->yres_virtual > info->fix.smem_len) {
619
                DPRINTK("no memory for screen (%ux%ux%u)\n",
620
                        var->xres, var->yres_virtual, var->bits_per_pixel);
621
                return -EINVAL;
622
        }
623
 
624
        if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
625
                DPRINTK("pixclock too high (%ldKHz)\n",
626
                        PICOS2KHZ(var->pixclock));
627
                return -EINVAL;
628
        }
629
 
630
        var->transp.offset = 0;
631
        var->transp.length = 0;
632
        switch (var->bits_per_pixel) {
633
        case 8:
634
                var->red.length = 8;
635
                var->green.length = 8;
636
                var->blue.length = 8;
637
                break;
638
        case 16:
639
                var->red.offset   = 11;
640
                var->red.length   = 5;
641
                var->green.offset = 5;
642
                var->green.length = 6;
643
                var->blue.offset  = 0;
644
                var->blue.length  = 5;
645
                break;
646
        case 32:
647
                var->transp.offset = 24;
648
                var->transp.length = 8;
649
                var->red.offset   = 16;
650
                var->green.offset = 8;
651
                var->blue.offset  = 0;
652
                var->red.length = 8;
653
                var->green.length = 8;
654
                var->blue.length = 8;
655
                break;
656
        case 24:
657
#ifdef __BIG_ENDIAN
658
                var->red.offset   = 0;
659
                var->blue.offset  = 16;
660
#else
661
                var->red.offset   = 16;
662
                var->blue.offset  = 0;
663
#endif
664
                var->green.offset = 8;
665
                var->red.length = 8;
666
                var->green.length = 8;
667
                var->blue.length = 8;
668
                break;
669
        }
670
        var->height = -1;
671
        var->width = -1;
672
 
673
        var->accel_flags = 0;    /* Can't mmap if this is on */
674
 
675
        DPRINTK("Checking graphics mode at %dx%d depth %d\n",
676
                var->xres, var->yres, var->bits_per_pixel);
677
        return 0;
678
}
679
 
680
/**
681
 *      pm2fb_set_par - Alters the hardware state.
682
 *      @info: frame buffer structure that represents a single frame buffer
683
 *
684
 *      Using the fb_var_screeninfo in fb_info we set the resolution of the
685
 *      this particular framebuffer.
686
 */
687
static int pm2fb_set_par(struct fb_info *info)
688
{
689
        struct pm2fb_par *par = info->par;
690
        u32 pixclock;
691
        u32 width = (info->var.xres_virtual + 7) & ~7;
692
        u32 height = info->var.yres_virtual;
693
        u32 depth = (info->var.bits_per_pixel + 7) & ~7;
694
        u32 hsstart, hsend, hbend, htotal;
695
        u32 vsstart, vsend, vbend, vtotal;
696
        u32 stride;
697
        u32 base;
698
        u32 video = 0;
699
        u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE;
700
        u32 txtmap = 0;
701
        u32 pixsize = 0;
702
        u32 clrformat = 0;
703
        u32 misc = 1; /* 8-bit DAC */
704
        u32 xres = (info->var.xres + 31) & ~31;
705
        int data64;
706
 
707
        reset_card(par);
708
        reset_config(par);
709
        clear_palette(par);
710
        if (par->memclock)
711
                set_memclock(par, par->memclock);
712
 
713
        depth = (depth > 32) ? 32 : depth;
714
        data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
715
 
716
        pixclock = PICOS2KHZ(info->var.pixclock);
717
        if (pixclock > PM2_MAX_PIXCLOCK) {
718
                DPRINTK("pixclock too high (%uKHz)\n", pixclock);
719
                return -EINVAL;
720
        }
721
 
722
        hsstart = to3264(info->var.right_margin, depth, data64);
723
        hsend = hsstart + to3264(info->var.hsync_len, depth, data64);
724
        hbend = hsend + to3264(info->var.left_margin, depth, data64);
725
        htotal = to3264(xres, depth, data64) + hbend - 1;
726
        vsstart = (info->var.lower_margin)
727
                ? info->var.lower_margin - 1
728
                : 0;     /* FIXME! */
729
        vsend = info->var.lower_margin + info->var.vsync_len - 1;
730
        vbend = info->var.lower_margin + info->var.vsync_len +
731
                info->var.upper_margin;
732
        vtotal = info->var.yres + vbend - 1;
733
        stride = to3264(width, depth, 1);
734
        base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
735
        if (data64)
736
                video |= PM2F_DATA_64_ENABLE;
737
 
738
        if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) {
739
                if (lowhsync) {
740
                        DPRINTK("ignoring +hsync, using -hsync.\n");
741
                        video |= PM2F_HSYNC_ACT_LOW;
742
                } else
743
                        video |= PM2F_HSYNC_ACT_HIGH;
744
        } else
745
                video |= PM2F_HSYNC_ACT_LOW;
746
 
747
        if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
748
                if (lowvsync) {
749
                        DPRINTK("ignoring +vsync, using -vsync.\n");
750
                        video |= PM2F_VSYNC_ACT_LOW;
751
                } else
752
                        video |= PM2F_VSYNC_ACT_HIGH;
753
        } else
754
                video |= PM2F_VSYNC_ACT_LOW;
755
 
756
        if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
757
                DPRINTK("interlaced not supported\n");
758
                return -EINVAL;
759
        }
760
        if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
761
                video |= PM2F_LINE_DOUBLE;
762
        if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
763
                video |= PM2F_VIDEO_ENABLE;
764
        par->video = video;
765
 
766
        info->fix.visual =
767
                (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
768
        info->fix.line_length = info->var.xres * depth / 8;
769
        info->cmap.len = 256;
770
 
771
        /*
772
         * Settings calculated. Now write them out.
773
         */
774
        if (par->type == PM2_TYPE_PERMEDIA2V) {
775
                WAIT_FIFO(par, 1);
776
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
777
        }
778
 
779
        set_aperture(par, depth);
780
 
781
        mb();
782
        WAIT_FIFO(par, 19);
783
        switch (depth) {
784
        case 8:
785
                pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
786
                clrformat = 0x2e;
787
                break;
788
        case 16:
789
                pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
790
                clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565;
791
                txtmap = PM2F_TEXTEL_SIZE_16;
792
                pixsize = 1;
793
                clrformat = 0x70;
794
                misc |= 8;
795
                break;
796
        case 32:
797
                pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
798
                clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888;
799
                txtmap = PM2F_TEXTEL_SIZE_32;
800
                pixsize = 2;
801
                clrformat = 0x20;
802
                misc |= 8;
803
                break;
804
        case 24:
805
                pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
806
                clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888;
807
                txtmap = PM2F_TEXTEL_SIZE_24;
808
                pixsize = 4;
809
                clrformat = 0x20;
810
                misc |= 8;
811
                break;
812
        }
813
        pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
814
        pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
815
        pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres));
816
        pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres));
817
        pm2_WR(par, PM2R_H_TOTAL, htotal);
818
        pm2_WR(par, PM2R_HS_START, hsstart);
819
        pm2_WR(par, PM2R_HS_END, hsend);
820
        pm2_WR(par, PM2R_HG_END, hbend);
821
        pm2_WR(par, PM2R_HB_END, hbend);
822
        pm2_WR(par, PM2R_V_TOTAL, vtotal);
823
        pm2_WR(par, PM2R_VS_START, vsstart);
824
        pm2_WR(par, PM2R_VS_END, vsend);
825
        pm2_WR(par, PM2R_VB_END, vbend);
826
        pm2_WR(par, PM2R_SCREEN_STRIDE, stride);
827
        wmb();
828
        pm2_WR(par, PM2R_WINDOW_ORIGIN, 0);
829
        pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width);
830
        pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
831
        wmb();
832
        pm2_WR(par, PM2R_SCREEN_BASE, base);
833
        wmb();
834
        set_video(par, video);
835
        WAIT_FIFO(par, 10);
836
        switch (par->type) {
837
        case PM2_TYPE_PERMEDIA2:
838
                pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode);
839
                pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
840
                                (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
841
                break;
842
        case PM2_TYPE_PERMEDIA2V:
843
                pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0);
844
                pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
845
                pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
846
                pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc);
847
                pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0);
848
                break;
849
        }
850
        set_pixclock(par, pixclock);
851
        DPRINTK("Setting graphics mode at %dx%d depth %d\n",
852
                info->var.xres, info->var.yres, info->var.bits_per_pixel);
853
        return 0;
854
}
855
 
856
/**
857
 *      pm2fb_setcolreg - Sets a color register.
858
 *      @regno: boolean, 0 copy local, 1 get_user() function
859
 *      @red: frame buffer colormap structure
860
 *      @green: The green value which can be up to 16 bits wide
861
 *      @blue:  The blue value which can be up to 16 bits wide.
862
 *      @transp: If supported the alpha value which can be up to 16 bits wide.
863
 *      @info: frame buffer info structure
864
 *
865
 *      Set a single color register. The values supplied have a 16 bit
866
 *      magnitude which needs to be scaled in this function for the hardware.
867
 *      Pretty much a direct lift from tdfxfb.c.
868
 *
869
 *      Returns negative errno on error, or zero on success.
870
 */
871
static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
872
                           unsigned blue, unsigned transp,
873
                           struct fb_info *info)
874
{
875
        struct pm2fb_par *par = info->par;
876
 
877
        if (regno >= info->cmap.len)  /* no. of hw registers */
878
                return -EINVAL;
879
        /*
880
         * Program hardware... do anything you want with transp
881
         */
882
 
883
        /* grayscale works only partially under directcolor */
884
        /* grayscale = 0.30*R + 0.59*G + 0.11*B */
885
        if (info->var.grayscale)
886
                red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
887
 
888
        /* Directcolor:
889
         *   var->{color}.offset contains start of bitfield
890
         *   var->{color}.length contains length of bitfield
891
         *   {hardwarespecific} contains width of DAC
892
         *   cmap[X] is programmed to
893
         *   (X << red.offset) | (X << green.offset) | (X << blue.offset)
894
         *   RAMDAC[X] is programmed to (red, green, blue)
895
         *
896
         * Pseudocolor:
897
         *    uses offset = 0 && length = DAC register width.
898
         *    var->{color}.offset is 0
899
         *    var->{color}.length contains widht of DAC
900
         *    cmap is not used
901
         *    DAC[X] is programmed to (red, green, blue)
902
         * Truecolor:
903
         *    does not use RAMDAC (usually has 3 of them).
904
         *    var->{color}.offset contains start of bitfield
905
         *    var->{color}.length contains length of bitfield
906
         *    cmap is programmed to
907
         *    (red << red.offset) | (green << green.offset) |
908
         *    (blue << blue.offset) | (transp << transp.offset)
909
         *    RAMDAC does not exist
910
         */
911
#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
912
        switch (info->fix.visual) {
913
        case FB_VISUAL_TRUECOLOR:
914
        case FB_VISUAL_PSEUDOCOLOR:
915
                red = CNVT_TOHW(red, info->var.red.length);
916
                green = CNVT_TOHW(green, info->var.green.length);
917
                blue = CNVT_TOHW(blue, info->var.blue.length);
918
                transp = CNVT_TOHW(transp, info->var.transp.length);
919
                break;
920
        case FB_VISUAL_DIRECTCOLOR:
921
                /* example here assumes 8 bit DAC. Might be different
922
                 * for your hardware */
923
                red = CNVT_TOHW(red, 8);
924
                green = CNVT_TOHW(green, 8);
925
                blue = CNVT_TOHW(blue, 8);
926
                /* hey, there is bug in transp handling... */
927
                transp = CNVT_TOHW(transp, 8);
928
                break;
929
        }
930
#undef CNVT_TOHW
931
        /* Truecolor has hardware independent palette */
932
        if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
933
                u32 v;
934
 
935
                if (regno >= 16)
936
                        return -EINVAL;
937
 
938
                v = (red << info->var.red.offset) |
939
                        (green << info->var.green.offset) |
940
                        (blue << info->var.blue.offset) |
941
                        (transp << info->var.transp.offset);
942
 
943
                switch (info->var.bits_per_pixel) {
944
                case 8:
945
                        break;
946
                case 16:
947
                case 24:
948
                case 32:
949
                        par->palette[regno] = v;
950
                        break;
951
                }
952
                return 0;
953
        } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
954
                set_color(par, regno, red, green, blue);
955
 
956
        return 0;
957
}
958
 
959
/**
960
 *      pm2fb_pan_display - Pans the display.
961
 *      @var: frame buffer variable screen structure
962
 *      @info: frame buffer structure that represents a single frame buffer
963
 *
964
 *      Pan (or wrap, depending on the `vmode' field) the display using the
965
 *      `xoffset' and `yoffset' fields of the `var' structure.
966
 *      If the values don't fit, return -EINVAL.
967
 *
968
 *      Returns negative errno on error, or zero on success.
969
 *
970
 */
971
static int pm2fb_pan_display(struct fb_var_screeninfo *var,
972
                             struct fb_info *info)
973
{
974
        struct pm2fb_par *p = info->par;
975
        u32 base;
976
        u32 depth = (var->bits_per_pixel + 7) & ~7;
977
        u32 xres = (var->xres + 31) & ~31;
978
 
979
        depth = (depth > 32) ? 32 : depth;
980
        base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
981
        WAIT_FIFO(p, 1);
982
        pm2_WR(p, PM2R_SCREEN_BASE, base);
983
        return 0;
984
}
985
 
986
/**
987
 *      pm2fb_blank - Blanks the display.
988
 *      @blank_mode: the blank mode we want.
989
 *      @info: frame buffer structure that represents a single frame buffer
990
 *
991
 *      Blank the screen if blank_mode != 0, else unblank. Return 0 if
992
 *      blanking succeeded, != 0 if un-/blanking failed due to e.g. a
993
 *      video mode which doesn't support it. Implements VESA suspend
994
 *      and powerdown modes on hardware that supports disabling hsync/vsync:
995
 *      blank_mode == 2: suspend vsync
996
 *      blank_mode == 3: suspend hsync
997
 *      blank_mode == 4: powerdown
998
 *
999
 *      Returns negative errno on error, or zero on success.
1000
 *
1001
 */
1002
static int pm2fb_blank(int blank_mode, struct fb_info *info)
1003
{
1004
        struct pm2fb_par *par = info->par;
1005
        u32 video = par->video;
1006
 
1007
        DPRINTK("blank_mode %d\n", blank_mode);
1008
 
1009
        switch (blank_mode) {
1010
        case FB_BLANK_UNBLANK:
1011
                /* Screen: On */
1012
                video |= PM2F_VIDEO_ENABLE;
1013
                break;
1014
        case FB_BLANK_NORMAL:
1015
                /* Screen: Off */
1016
                video &= ~PM2F_VIDEO_ENABLE;
1017
                break;
1018
        case FB_BLANK_VSYNC_SUSPEND:
1019
                /* VSync: Off */
1020
                video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW);
1021
                break;
1022
        case FB_BLANK_HSYNC_SUSPEND:
1023
                /* HSync: Off */
1024
                video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
1025
                break;
1026
        case FB_BLANK_POWERDOWN:
1027
                /* HSync: Off, VSync: Off */
1028
                video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
1029
                break;
1030
        }
1031
        set_video(par, video);
1032
        return 0;
1033
}
1034
 
1035
static int pm2fb_sync(struct fb_info *info)
1036
{
1037
        struct pm2fb_par *par = info->par;
1038
 
1039
        WAIT_FIFO(par, 1);
1040
        pm2_WR(par, PM2R_SYNC, 0);
1041
        mb();
1042
        do {
1043
                while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
1044
                        cpu_relax();
1045
        } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
1046
 
1047
        return 0;
1048
}
1049
 
1050
static void pm2fb_fillrect(struct fb_info *info,
1051
                                const struct fb_fillrect *region)
1052
{
1053
        struct pm2fb_par *par = info->par;
1054
        struct fb_fillrect modded;
1055
        int vxres, vyres;
1056
        u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
1057
                ((u32 *)info->pseudo_palette)[region->color] : region->color;
1058
 
1059
        if (info->state != FBINFO_STATE_RUNNING)
1060
                return;
1061
        if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
1062
                region->rop != ROP_COPY ) {
1063
                cfb_fillrect(info, region);
1064
                return;
1065
        }
1066
 
1067
        vxres = info->var.xres_virtual;
1068
        vyres = info->var.yres_virtual;
1069
 
1070
        memcpy(&modded, region, sizeof(struct fb_fillrect));
1071
 
1072
        if (!modded.width || !modded.height ||
1073
            modded.dx >= vxres || modded.dy >= vyres)
1074
                return;
1075
 
1076
        if (modded.dx + modded.width  > vxres)
1077
                modded.width  = vxres - modded.dx;
1078
        if (modded.dy + modded.height > vyres)
1079
                modded.height = vyres - modded.dy;
1080
 
1081
        if (info->var.bits_per_pixel == 8)
1082
                color |= color << 8;
1083
        if (info->var.bits_per_pixel <= 16)
1084
                color |= color << 16;
1085
 
1086
        WAIT_FIFO(par, 3);
1087
        pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE);
1088
        pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
1089
        pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
1090
        if (info->var.bits_per_pixel != 24) {
1091
                WAIT_FIFO(par, 2);
1092
                pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
1093
                wmb();
1094
                pm2_WR(par, PM2R_RENDER,
1095
                                PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL);
1096
        } else {
1097
                WAIT_FIFO(par, 4);
1098
                pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
1099
                pm2_WR(par, PM2R_CONSTANT_COLOR, color);
1100
                wmb();
1101
                pm2_WR(par, PM2R_RENDER,
1102
                                PM2F_RENDER_RECTANGLE |
1103
                                PM2F_INCREASE_X | PM2F_INCREASE_Y );
1104
                pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
1105
        }
1106
}
1107
 
1108
static void pm2fb_copyarea(struct fb_info *info,
1109
                                const struct fb_copyarea *area)
1110
{
1111
        struct pm2fb_par *par = info->par;
1112
        struct fb_copyarea modded;
1113
        u32 vxres, vyres;
1114
 
1115
        if (info->state != FBINFO_STATE_RUNNING)
1116
                return;
1117
        if (info->flags & FBINFO_HWACCEL_DISABLED) {
1118
                cfb_copyarea(info, area);
1119
                return;
1120
        }
1121
 
1122
        memcpy(&modded, area, sizeof(struct fb_copyarea));
1123
 
1124
        vxres = info->var.xres_virtual;
1125
        vyres = info->var.yres_virtual;
1126
 
1127
        if (!modded.width || !modded.height ||
1128
            modded.sx >= vxres || modded.sy >= vyres ||
1129
            modded.dx >= vxres || modded.dy >= vyres)
1130
                return;
1131
 
1132
        if (modded.sx + modded.width > vxres)
1133
                modded.width = vxres - modded.sx;
1134
        if (modded.dx + modded.width > vxres)
1135
                modded.width = vxres - modded.dx;
1136
        if (modded.sy + modded.height > vyres)
1137
                modded.height = vyres - modded.sy;
1138
        if (modded.dy + modded.height > vyres)
1139
                modded.height = vyres - modded.dy;
1140
 
1141
        WAIT_FIFO(par, 5);
1142
        pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
1143
                PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
1144
        pm2_WR(par, PM2R_FB_SOURCE_DELTA,
1145
                        ((modded.sy - modded.dy) & 0xfff) << 16 |
1146
                        ((modded.sx - modded.dx) & 0xfff));
1147
        pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
1148
        pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
1149
        wmb();
1150
        pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
1151
                                (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) |
1152
                                (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0));
1153
}
1154
 
1155
static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
1156
{
1157
        struct pm2fb_par *par = info->par;
1158
        u32 height = image->height;
1159
        u32 fgx, bgx;
1160
        const u32 *src = (const u32 *)image->data;
1161
        u32 xres = (info->var.xres + 31) & ~31;
1162
 
1163
        if (info->state != FBINFO_STATE_RUNNING)
1164
                return;
1165
        if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) {
1166
                cfb_imageblit(info, image);
1167
                return;
1168
        }
1169
        switch (info->fix.visual) {
1170
        case FB_VISUAL_PSEUDOCOLOR:
1171
                fgx = image->fg_color;
1172
                bgx = image->bg_color;
1173
                break;
1174
        case FB_VISUAL_TRUECOLOR:
1175
        default:
1176
                fgx = par->palette[image->fg_color];
1177
                bgx = par->palette[image->bg_color];
1178
                break;
1179
        }
1180
        if (info->var.bits_per_pixel == 8) {
1181
                fgx |= fgx << 8;
1182
                bgx |= bgx << 8;
1183
        }
1184
        if (info->var.bits_per_pixel <= 16) {
1185
                fgx |= fgx << 16;
1186
                bgx |= bgx << 16;
1187
        }
1188
 
1189
        WAIT_FIFO(par, 13);
1190
        pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
1191
        pm2_WR(par, PM2R_SCISSOR_MIN_XY,
1192
                        ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
1193
        pm2_WR(par, PM2R_SCISSOR_MAX_XY,
1194
                        (((image->dy + image->height) & 0x0fff) << 16) |
1195
                        ((image->dx + image->width) & 0x0fff));
1196
        pm2_WR(par, PM2R_SCISSOR_MODE, 1);
1197
        /* GXcopy & UNIT_ENABLE */
1198
        pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1);
1199
        pm2_WR(par, PM2R_RECTANGLE_ORIGIN,
1200
                        ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
1201
        pm2_WR(par, PM2R_RECTANGLE_SIZE,
1202
                        ((image->height & 0x0fff) << 16) |
1203
                        ((image->width) & 0x0fff));
1204
        if (info->var.bits_per_pixel == 24) {
1205
                pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
1206
                /* clear area */
1207
                pm2_WR(par, PM2R_CONSTANT_COLOR, bgx);
1208
                pm2_WR(par, PM2R_RENDER,
1209
                        PM2F_RENDER_RECTANGLE |
1210
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
1211
                /* BitMapPackEachScanline & invert bits and byte order*/
1212
                /* force background */
1213
                pm2_WR(par, PM2R_RASTERIZER_MODE,  (1 << 9) | 1 | (3 << 7));
1214
                pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
1215
                pm2_WR(par, PM2R_RENDER,
1216
                        PM2F_RENDER_RECTANGLE |
1217
                        PM2F_INCREASE_X | PM2F_INCREASE_Y |
1218
                        PM2F_RENDER_SYNC_ON_BIT_MASK);
1219
        } else {
1220
                pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
1221
                /* clear area */
1222
                pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx);
1223
                pm2_WR(par, PM2R_RENDER,
1224
                        PM2F_RENDER_RECTANGLE |
1225
                        PM2F_RENDER_FASTFILL |
1226
                        PM2F_INCREASE_X | PM2F_INCREASE_Y);
1227
                /* invert bits and byte order*/
1228
                pm2_WR(par, PM2R_RASTERIZER_MODE,  1 | (3 << 7));
1229
                pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
1230
                pm2_WR(par, PM2R_RENDER,
1231
                        PM2F_RENDER_RECTANGLE |
1232
                        PM2F_INCREASE_X | PM2F_INCREASE_Y |
1233
                        PM2F_RENDER_FASTFILL |
1234
                        PM2F_RENDER_SYNC_ON_BIT_MASK);
1235
        }
1236
 
1237
        while (height--) {
1238
                int width = ((image->width + 7) >> 3)
1239
                                + info->pixmap.scan_align - 1;
1240
                width >>= 2;
1241
                WAIT_FIFO(par, width);
1242
                while (width--) {
1243
                        pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src);
1244
                        src++;
1245
                }
1246
        }
1247
        WAIT_FIFO(par, 3);
1248
        pm2_WR(par, PM2R_RASTERIZER_MODE, 0);
1249
        pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
1250
        pm2_WR(par, PM2R_SCISSOR_MODE, 0);
1251
}
1252
 
1253
/*
1254
 *      Hardware cursor support.
1255
 */
1256
static const u8 cursor_bits_lookup[16] = {
1257
        0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1258
        0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1259
};
1260
 
1261
static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1262
{
1263
        struct pm2fb_par *par = info->par;
1264
        u8 mode = PM2F_CURSORMODE_TYPE_X;
1265
        int x = cursor->image.dx - info->var.xoffset;
1266
        int y = cursor->image.dy - info->var.yoffset;
1267
 
1268
        if (cursor->enable)
1269
                mode |= PM2F_CURSORMODE_CURSOR_ENABLE;
1270
 
1271
        pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode);
1272
 
1273
        if (!cursor->enable)
1274
                x = 2047;       /* push it outside display */
1275
        pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
1276
        pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
1277
        pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
1278
        pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
1279
 
1280
        /*
1281
         * If the cursor is not be changed this means either we want the
1282
         * current cursor state (if enable is set) or we want to query what
1283
         * we can do with the cursor (if enable is not set)
1284
         */
1285
        if (!cursor->set)
1286
                return 0;
1287
 
1288
        if (cursor->set & FB_CUR_SETHOT) {
1289
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT,
1290
                             cursor->hot.x & 0x3f);
1291
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT,
1292
                             cursor->hot.y & 0x3f);
1293
        }
1294
 
1295
        if (cursor->set & FB_CUR_SETCMAP) {
1296
                u32 fg_idx = cursor->image.fg_color;
1297
                u32 bg_idx = cursor->image.bg_color;
1298
                struct fb_cmap cmap = info->cmap;
1299
 
1300
                /* the X11 driver says one should use these color registers */
1301
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
1302
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0,
1303
                             cmap.red[bg_idx] >> 8 );
1304
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1,
1305
                             cmap.green[bg_idx] >> 8 );
1306
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2,
1307
                             cmap.blue[bg_idx] >> 8 );
1308
 
1309
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3,
1310
                             cmap.red[fg_idx] >> 8 );
1311
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4,
1312
                             cmap.green[fg_idx] >> 8 );
1313
                pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5,
1314
                             cmap.blue[fg_idx] >> 8 );
1315
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
1316
        }
1317
 
1318
        if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
1319
                u8 *bitmap = (u8 *)cursor->image.data;
1320
                u8 *mask = (u8 *)cursor->mask;
1321
                int i;
1322
                int pos = PM2VI_RD_CURSOR_PATTERN;
1323
 
1324
                for (i = 0; i < cursor->image.height; i++) {
1325
                        int j = (cursor->image.width + 7) >> 3;
1326
                        int k = 8 - j;
1327
 
1328
                        pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
1329
 
1330
                        for (; j > 0; j--) {
1331
                                u8 data = *bitmap ^ *mask;
1332
 
1333
                                if (cursor->rop == ROP_COPY)
1334
                                        data = *mask & *bitmap;
1335
                                /* Upper 4 bits of bitmap data */
1336
                                pm2v_RDAC_WR(par, pos++,
1337
                                        cursor_bits_lookup[data >> 4] |
1338
                                        (cursor_bits_lookup[*mask >> 4] << 1));
1339
                                /* Lower 4 bits of bitmap */
1340
                                pm2v_RDAC_WR(par, pos++,
1341
                                        cursor_bits_lookup[data & 0xf] |
1342
                                        (cursor_bits_lookup[*mask & 0xf] << 1));
1343
                                bitmap++;
1344
                                mask++;
1345
                        }
1346
                        for (; k > 0; k--) {
1347
                                pm2v_RDAC_WR(par, pos++, 0);
1348
                                pm2v_RDAC_WR(par, pos++, 0);
1349
                        }
1350
                }
1351
 
1352
                while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) {
1353
                        pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
1354
                        pm2v_RDAC_WR(par, pos++, 0);
1355
                }
1356
 
1357
                pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
1358
        }
1359
        return 0;
1360
}
1361
 
1362
static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1363
{
1364
        struct pm2fb_par *par = info->par;
1365
        u8 mode;
1366
 
1367
        if (!hwcursor)
1368
                return -EINVAL; /* just to force soft_cursor() call */
1369
 
1370
        /* Too large of a cursor or wrong bpp :-( */
1371
        if (cursor->image.width > 64 ||
1372
            cursor->image.height > 64 ||
1373
            cursor->image.depth > 1)
1374
                return -EINVAL;
1375
 
1376
        if (par->type == PM2_TYPE_PERMEDIA2V)
1377
                return pm2vfb_cursor(info, cursor);
1378
 
1379
        mode = 0x40;
1380
        if (cursor->enable)
1381
                 mode = 0x43;
1382
 
1383
        pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode);
1384
 
1385
        /*
1386
         * If the cursor is not be changed this means either we want the
1387
         * current cursor state (if enable is set) or we want to query what
1388
         * we can do with the cursor (if enable is not set)
1389
         */
1390
        if (!cursor->set)
1391
                return 0;
1392
 
1393
        if (cursor->set & FB_CUR_SETPOS) {
1394
                int x = cursor->image.dx - info->var.xoffset + 63;
1395
                int y = cursor->image.dy - info->var.yoffset + 63;
1396
 
1397
                WAIT_FIFO(par, 4);
1398
                pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff);
1399
                pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7);
1400
                pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff);
1401
                pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7);
1402
        }
1403
 
1404
        if (cursor->set & FB_CUR_SETCMAP) {
1405
                u32 fg_idx = cursor->image.fg_color;
1406
                u32 bg_idx = cursor->image.bg_color;
1407
 
1408
                WAIT_FIFO(par, 7);
1409
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1);
1410
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1411
                        info->cmap.red[bg_idx] >> 8);
1412
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1413
                        info->cmap.green[bg_idx] >> 8);
1414
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1415
                        info->cmap.blue[bg_idx] >> 8);
1416
 
1417
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1418
                        info->cmap.red[fg_idx] >> 8);
1419
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1420
                        info->cmap.green[fg_idx] >> 8);
1421
                pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
1422
                        info->cmap.blue[fg_idx] >> 8);
1423
        }
1424
 
1425
        if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
1426
                u8 *bitmap = (u8 *)cursor->image.data;
1427
                u8 *mask = (u8 *)cursor->mask;
1428
                int i;
1429
 
1430
                WAIT_FIFO(par, 1);
1431
                pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
1432
 
1433
                for (i = 0; i < cursor->image.height; i++) {
1434
                        int j = (cursor->image.width + 7) >> 3;
1435
                        int k = 8 - j;
1436
 
1437
                        WAIT_FIFO(par, 8);
1438
                        for (; j > 0; j--) {
1439
                                u8 data = *bitmap ^ *mask;
1440
 
1441
                                if (cursor->rop == ROP_COPY)
1442
                                        data = *mask & *bitmap;
1443
                                /* bitmap data */
1444
                                pm2_WR(par, PM2R_RD_CURSOR_DATA, data);
1445
                                bitmap++;
1446
                                mask++;
1447
                        }
1448
                        for (; k > 0; k--)
1449
                                pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1450
                }
1451
                for (; i < 64; i++) {
1452
                        int j = 8;
1453
                        WAIT_FIFO(par, 8);
1454
                        while (j-- > 0)
1455
                                pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1456
                }
1457
 
1458
                mask = (u8 *)cursor->mask;
1459
                for (i = 0; i < cursor->image.height; i++) {
1460
                        int j = (cursor->image.width + 7) >> 3;
1461
                        int k = 8 - j;
1462
 
1463
                        WAIT_FIFO(par, 8);
1464
                        for (; j > 0; j--) {
1465
                                /* mask */
1466
                                pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask);
1467
                                mask++;
1468
                        }
1469
                        for (; k > 0; k--)
1470
                                pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1471
                }
1472
                for (; i < 64; i++) {
1473
                        int j = 8;
1474
                        WAIT_FIFO(par, 8);
1475
                        while (j-- > 0)
1476
                                pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
1477
                }
1478
        }
1479
        return 0;
1480
}
1481
 
1482
/* ------------ Hardware Independent Functions ------------ */
1483
 
1484
/*
1485
 *  Frame buffer operations
1486
 */
1487
 
1488
static struct fb_ops pm2fb_ops = {
1489
        .owner          = THIS_MODULE,
1490
        .fb_check_var   = pm2fb_check_var,
1491
        .fb_set_par     = pm2fb_set_par,
1492
        .fb_setcolreg   = pm2fb_setcolreg,
1493
        .fb_blank       = pm2fb_blank,
1494
        .fb_pan_display = pm2fb_pan_display,
1495
        .fb_fillrect    = pm2fb_fillrect,
1496
        .fb_copyarea    = pm2fb_copyarea,
1497
        .fb_imageblit   = pm2fb_imageblit,
1498
        .fb_sync        = pm2fb_sync,
1499
        .fb_cursor      = pm2fb_cursor,
1500
};
1501
 
1502
/*
1503
 * PCI stuff
1504
 */
1505
 
1506
 
1507
/**
1508
 * Device initialisation
1509
 *
1510
 * Initialise and allocate resource for PCI device.
1511
 *
1512
 * @param       pdev    PCI device.
1513
 * @param       id      PCI device ID.
1514
 */
1515
static int __devinit pm2fb_probe(struct pci_dev *pdev,
1516
                                 const struct pci_device_id *id)
1517
{
1518
        struct pm2fb_par *default_par;
1519
        struct fb_info *info;
1520
        int err;
1521
        int retval = -ENXIO;
1522
 
1523
        err = pci_enable_device(pdev);
1524
        if (err) {
1525
                printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
1526
                return err;
1527
        }
1528
 
1529
        info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev);
1530
        if (!info)
1531
                return -ENOMEM;
1532
        default_par = info->par;
1533
 
1534
        switch (pdev->device) {
1535
        case  PCI_DEVICE_ID_TI_TVP4020:
1536
                strcpy(pm2fb_fix.id, "TVP4020");
1537
                default_par->type = PM2_TYPE_PERMEDIA2;
1538
                break;
1539
        case  PCI_DEVICE_ID_3DLABS_PERMEDIA2:
1540
                strcpy(pm2fb_fix.id, "Permedia2");
1541
                default_par->type = PM2_TYPE_PERMEDIA2;
1542
                break;
1543
        case  PCI_DEVICE_ID_3DLABS_PERMEDIA2V:
1544
                strcpy(pm2fb_fix.id, "Permedia2v");
1545
                default_par->type = PM2_TYPE_PERMEDIA2V;
1546
                break;
1547
        }
1548
 
1549
        pm2fb_fix.mmio_start = pci_resource_start(pdev, 0);
1550
        pm2fb_fix.mmio_len = PM2_REGS_SIZE;
1551
 
1552
#if defined(__BIG_ENDIAN)
1553
        /*
1554
         * PM2 has a 64k register file, mapped twice in 128k. Lower
1555
         * map is little-endian, upper map is big-endian.
1556
         */
1557
        pm2fb_fix.mmio_start += PM2_REGS_SIZE;
1558
        DPRINTK("Adjusting register base for big-endian.\n");
1559
#endif
1560
        DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
1561
 
1562
        /* Registers - request region and map it. */
1563
        if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
1564
                                "pm2fb regbase")) {
1565
                printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
1566
                goto err_exit_neither;
1567
        }
1568
        default_par->v_regs =
1569
                ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1570
        if (!default_par->v_regs) {
1571
                printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
1572
                       pm2fb_fix.id);
1573
                release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1574
                goto err_exit_neither;
1575
        }
1576
 
1577
        /* Stash away memory register info for use when we reset the board */
1578
        default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL);
1579
        default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS);
1580
        default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG);
1581
        DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x\n",
1582
                default_par->mem_control, default_par->boot_address,
1583
                default_par->mem_config);
1584
 
1585
        if (default_par->mem_control == 0 &&
1586
                default_par->boot_address == 0x31 &&
1587
                default_par->mem_config == 0x259fffff) {
1588
                default_par->memclock = CVPPC_MEMCLOCK;
1589
                default_par->mem_control = 0;
1590
                default_par->boot_address = 0x20;
1591
                default_par->mem_config = 0xe6002021;
1592
                if (pdev->subsystem_vendor == 0x1048 &&
1593
                        pdev->subsystem_device == 0x0a31) {
1594
                        DPRINTK("subsystem_vendor: %04x, "
1595
                                "subsystem_device: %04x\n",
1596
                                pdev->subsystem_vendor, pdev->subsystem_device);
1597
                        DPRINTK("We have not been initialized by VGA BIOS and "
1598
                                "are running on an Elsa Winner 2000 Office\n");
1599
                        DPRINTK("Initializing card timings manually...\n");
1600
                        default_par->memclock = 100000;
1601
                }
1602
                if (pdev->subsystem_vendor == 0x3d3d &&
1603
                        pdev->subsystem_device == 0x0100) {
1604
                        DPRINTK("subsystem_vendor: %04x, "
1605
                                "subsystem_device: %04x\n",
1606
                                pdev->subsystem_vendor, pdev->subsystem_device);
1607
                        DPRINTK("We have not been initialized by VGA BIOS and "
1608
                                "are running on an 3dlabs reference board\n");
1609
                        DPRINTK("Initializing card timings manually...\n");
1610
                        default_par->memclock = 74894;
1611
                }
1612
        }
1613
 
1614
        /* Now work out how big lfb is going to be. */
1615
        switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1616
        case PM2F_MEM_BANKS_1:
1617
                pm2fb_fix.smem_len = 0x200000;
1618
                break;
1619
        case PM2F_MEM_BANKS_2:
1620
                pm2fb_fix.smem_len = 0x400000;
1621
                break;
1622
        case PM2F_MEM_BANKS_3:
1623
                pm2fb_fix.smem_len = 0x600000;
1624
                break;
1625
        case PM2F_MEM_BANKS_4:
1626
                pm2fb_fix.smem_len = 0x800000;
1627
                break;
1628
        }
1629
        pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
1630
 
1631
        /* Linear frame buffer - request region and map it. */
1632
        if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
1633
                                "pm2fb smem")) {
1634
                printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
1635
                goto err_exit_mmio;
1636
        }
1637
        info->screen_base =
1638
                ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1639
        if (!info->screen_base) {
1640
                printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
1641
                release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1642
                goto err_exit_mmio;
1643
        }
1644
 
1645
#ifdef CONFIG_MTRR
1646
        default_par->mtrr_handle = -1;
1647
        if (!nomtrr)
1648
                default_par->mtrr_handle =
1649
                        mtrr_add(pm2fb_fix.smem_start,
1650
                                 pm2fb_fix.smem_len,
1651
                                 MTRR_TYPE_WRCOMB, 1);
1652
#endif
1653
 
1654
        info->fbops             = &pm2fb_ops;
1655
        info->fix               = pm2fb_fix;
1656
        info->pseudo_palette    = default_par->palette;
1657
        info->flags             = FBINFO_DEFAULT |
1658
                                  FBINFO_HWACCEL_YPAN |
1659
                                  FBINFO_HWACCEL_COPYAREA |
1660
                                  FBINFO_HWACCEL_IMAGEBLIT |
1661
                                  FBINFO_HWACCEL_FILLRECT;
1662
 
1663
        info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL);
1664
        if (!info->pixmap.addr) {
1665
                retval = -ENOMEM;
1666
                goto err_exit_pixmap;
1667
        }
1668
        info->pixmap.size = PM2_PIXMAP_SIZE;
1669
        info->pixmap.buf_align = 4;
1670
        info->pixmap.scan_align = 4;
1671
        info->pixmap.access_align = 32;
1672
        info->pixmap.flags = FB_PIXMAP_SYSTEM;
1673
 
1674
        if (noaccel) {
1675
                printk(KERN_DEBUG "disabling acceleration\n");
1676
                info->flags |= FBINFO_HWACCEL_DISABLED;
1677
                info->pixmap.scan_align = 1;
1678
        }
1679
 
1680
        if (!mode)
1681
                mode = "640x480@60";
1682
 
1683
        err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8);
1684
        if (!err || err == 4)
1685
                info->var = pm2fb_var;
1686
 
1687
        if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
1688
                goto err_exit_both;
1689
 
1690
        if (register_framebuffer(info) < 0)
1691
                goto err_exit_all;
1692
 
1693
        printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n",
1694
               info->node, info->fix.id, pm2fb_fix.smem_len / 1024);
1695
 
1696
        /*
1697
         * Our driver data
1698
         */
1699
        pci_set_drvdata(pdev, info);
1700
 
1701
        return 0;
1702
 
1703
 err_exit_all:
1704
        fb_dealloc_cmap(&info->cmap);
1705
 err_exit_both:
1706
        kfree(info->pixmap.addr);
1707
 err_exit_pixmap:
1708
        iounmap(info->screen_base);
1709
        release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
1710
 err_exit_mmio:
1711
        iounmap(default_par->v_regs);
1712
        release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
1713
 err_exit_neither:
1714
        framebuffer_release(info);
1715
        return retval;
1716
}
1717
 
1718
/**
1719
 * Device removal.
1720
 *
1721
 * Release all device resources.
1722
 *
1723
 * @param       pdev    PCI device to clean up.
1724
 */
1725
static void __devexit pm2fb_remove(struct pci_dev *pdev)
1726
{
1727
        struct fb_info *info = pci_get_drvdata(pdev);
1728
        struct fb_fix_screeninfo *fix = &info->fix;
1729
        struct pm2fb_par *par = info->par;
1730
 
1731
        unregister_framebuffer(info);
1732
 
1733
#ifdef CONFIG_MTRR
1734
        if (par->mtrr_handle >= 0)
1735
                mtrr_del(par->mtrr_handle, info->fix.smem_start,
1736
                         info->fix.smem_len);
1737
#endif /* CONFIG_MTRR */
1738
        iounmap(info->screen_base);
1739
        release_mem_region(fix->smem_start, fix->smem_len);
1740
        iounmap(par->v_regs);
1741
        release_mem_region(fix->mmio_start, fix->mmio_len);
1742
 
1743
        pci_set_drvdata(pdev, NULL);
1744
        kfree(info->pixmap.addr);
1745
        kfree(info);
1746
}
1747
 
1748
static struct pci_device_id pm2fb_id_table[] = {
1749
        { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
1750
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1751
        { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
1752
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1753
        { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
1754
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1755
        { 0, }
1756
};
1757
 
1758
static struct pci_driver pm2fb_driver = {
1759
        .name           = "pm2fb",
1760
        .id_table       = pm2fb_id_table,
1761
        .probe          = pm2fb_probe,
1762
        .remove         = __devexit_p(pm2fb_remove),
1763
};
1764
 
1765
MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
1766
 
1767
 
1768
#ifndef MODULE
1769
/**
1770
 * Parse user speficied options.
1771
 *
1772
 * This is, comma-separated options following `video=pm2fb:'.
1773
 */
1774
static int __init pm2fb_setup(char *options)
1775
{
1776
        char *this_opt;
1777
 
1778
        if (!options || !*options)
1779
                return 0;
1780
 
1781
        while ((this_opt = strsep(&options, ",")) != NULL) {
1782
                if (!*this_opt)
1783
                        continue;
1784
                if (!strcmp(this_opt, "lowhsync"))
1785
                        lowhsync = 1;
1786
                else if (!strcmp(this_opt, "lowvsync"))
1787
                        lowvsync = 1;
1788
                else if (!strncmp(this_opt, "hwcursor=", 9))
1789
                        hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
1790
#ifdef CONFIG_MTRR
1791
                else if (!strncmp(this_opt, "nomtrr", 6))
1792
                        nomtrr = 1;
1793
#endif
1794
                else if (!strncmp(this_opt, "noaccel", 7))
1795
                        noaccel = 1;
1796
                else
1797
                        mode = this_opt;
1798
        }
1799
        return 0;
1800
}
1801
#endif
1802
 
1803
 
1804
static int __init pm2fb_init(void)
1805
{
1806
#ifndef MODULE
1807
        char *option = NULL;
1808
 
1809
        if (fb_get_options("pm2fb", &option))
1810
                return -ENODEV;
1811
        pm2fb_setup(option);
1812
#endif
1813
 
1814
        return pci_register_driver(&pm2fb_driver);
1815
}
1816
 
1817
module_init(pm2fb_init);
1818
 
1819
#ifdef MODULE
1820
/*
1821
 *  Cleanup
1822
 */
1823
 
1824
static void __exit pm2fb_exit(void)
1825
{
1826
        pci_unregister_driver(&pm2fb_driver);
1827
}
1828
#endif
1829
 
1830
#ifdef MODULE
1831
module_exit(pm2fb_exit);
1832
 
1833
module_param(mode, charp, 0);
1834
MODULE_PARM_DESC(mode, "Preferred video mode e.g. '648x480-8@60'");
1835
module_param(lowhsync, bool, 0);
1836
MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
1837
module_param(lowvsync, bool, 0);
1838
MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");
1839
module_param(noaccel, bool, 0);
1840
MODULE_PARM_DESC(noaccel, "Disable acceleration");
1841
module_param(hwcursor, int, 0644);
1842
MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1843
                        "(1=enable, 0=disable, default=1)");
1844
#ifdef CONFIG_MTRR
1845
module_param(nomtrr, bool, 0);
1846
MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
1847
#endif
1848
 
1849
MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
1850
MODULE_DESCRIPTION("Permedia2 framebuffer device driver");
1851
MODULE_LICENSE("GPL");
1852
#endif

powered by: WebSVN 2.1.0

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