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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  linux/drivers/video/cyber2000fb.c
3
 *
4
 *  Copyright (C) 1998-2002 Russell King
5
 *
6
 *  MIPS and 50xx clock support
7
 *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
8
 *
9
 *  32 bit support, text color and panning fixes for modes != 8 bit
10
 *  Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License version 2 as
14
 * published by the Free Software Foundation.
15
 *
16
 * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
17
 *
18
 * Based on cyberfb.c.
19
 *
20
 * Note that we now use the new fbcon fix, var and cmap scheme.  We do
21
 * still have to check which console is the currently displayed one
22
 * however, especially for the colourmap stuff.
23
 *
24
 * We also use the new hotplug PCI subsystem.  I'm not sure if there
25
 * are any such cards, but I'm erring on the side of caution.  We don't
26
 * want to go pop just because someone does have one.
27
 *
28
 * Note that this doesn't work fully in the case of multiple CyberPro
29
 * cards with grabbers.  We currently can only attach to the first
30
 * CyberPro card found.
31
 *
32
 * When we're in truecolour mode, we power down the LUT RAM as a power
33
 * saving feature.  Also, when we enter any of the powersaving modes
34
 * (except soft blanking) we power down the RAMDACs.  This saves about
35
 * 1W, which is roughly 8% of the power consumption of a NetWinder
36
 * (which, incidentally, is about the same saving as a 2.5in hard disk
37
 * entering standby mode.)
38
 */
39
#include <linux/module.h>
40
#include <linux/kernel.h>
41
#include <linux/errno.h>
42
#include <linux/string.h>
43
#include <linux/mm.h>
44
#include <linux/slab.h>
45
#include <linux/delay.h>
46
#include <linux/fb.h>
47
#include <linux/pci.h>
48
#include <linux/init.h>
49
 
50
#include <asm/io.h>
51
#include <asm/pgtable.h>
52
#include <asm/system.h>
53
 
54
#ifdef __arm__
55
#include <asm/mach-types.h>
56
#endif
57
 
58
#include "cyber2000fb.h"
59
 
60
struct cfb_info {
61
        struct fb_info          fb;
62
        struct display_switch   *dispsw;
63
        struct display          *display;
64
        struct pci_dev          *dev;
65
        unsigned char           __iomem *region;
66
        unsigned char           __iomem *regs;
67
        u_int                   id;
68
        int                     func_use_count;
69
        u_long                  ref_ps;
70
 
71
        /*
72
         * Clock divisors
73
         */
74
        u_int                   divisors[4];
75
 
76
        struct {
77
                u8 red, green, blue;
78
        } palette[NR_PALETTE];
79
 
80
        u_char                  mem_ctl1;
81
        u_char                  mem_ctl2;
82
        u_char                  mclk_mult;
83
        u_char                  mclk_div;
84
        /*
85
         * RAMDAC control register is both of these or'ed together
86
         */
87
        u_char                  ramdac_ctrl;
88
        u_char                  ramdac_powerdown;
89
 
90
        u32                     pseudo_palette[16];
91
};
92
 
93
static char *default_font = "Acorn8x8";
94
module_param(default_font, charp, 0);
95
MODULE_PARM_DESC(default_font, "Default font name");
96
 
97
/*
98
 * Our access methods.
99
 */
100
#define cyber2000fb_writel(val, reg, cfb)       writel(val, (cfb)->regs + (reg))
101
#define cyber2000fb_writew(val, reg, cfb)       writew(val, (cfb)->regs + (reg))
102
#define cyber2000fb_writeb(val, reg, cfb)       writeb(val, (cfb)->regs + (reg))
103
 
104
#define cyber2000fb_readb(reg, cfb)             readb((cfb)->regs + (reg))
105
 
106
static inline void
107
cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
108
{
109
        cyber2000fb_writew((reg & 255) | val << 8, 0x3d4, cfb);
110
}
111
 
112
static inline void
113
cyber2000_grphw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
114
{
115
        cyber2000fb_writew((reg & 255) | val << 8, 0x3ce, cfb);
116
}
117
 
118
static inline unsigned int
119
cyber2000_grphr(unsigned int reg, struct cfb_info *cfb)
120
{
121
        cyber2000fb_writeb(reg, 0x3ce, cfb);
122
        return cyber2000fb_readb(0x3cf, cfb);
123
}
124
 
125
static inline void
126
cyber2000_attrw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
127
{
128
        cyber2000fb_readb(0x3da, cfb);
129
        cyber2000fb_writeb(reg, 0x3c0, cfb);
130
        cyber2000fb_readb(0x3c1, cfb);
131
        cyber2000fb_writeb(val, 0x3c0, cfb);
132
}
133
 
134
static inline void
135
cyber2000_seqw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
136
{
137
        cyber2000fb_writew((reg & 255) | val << 8, 0x3c4, cfb);
138
}
139
 
140
/* -------------------- Hardware specific routines ------------------------- */
141
 
142
/*
143
 * Hardware Cyber2000 Acceleration
144
 */
145
static void
146
cyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
147
{
148
        struct cfb_info *cfb = (struct cfb_info *)info;
149
        unsigned long dst, col;
150
 
151
        if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
152
                cfb_fillrect(info, rect);
153
                return;
154
        }
155
 
156
        cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
157
        cyber2000fb_writew(rect->width - 1, CO_REG_PIXWIDTH, cfb);
158
        cyber2000fb_writew(rect->height - 1, CO_REG_PIXHEIGHT, cfb);
159
 
160
        col = rect->color;
161
        if (cfb->fb.var.bits_per_pixel > 8)
162
                col = ((u32 *)cfb->fb.pseudo_palette)[col];
163
        cyber2000fb_writel(col, CO_REG_FGCOLOUR, cfb);
164
 
165
        dst = rect->dx + rect->dy * cfb->fb.var.xres_virtual;
166
        if (cfb->fb.var.bits_per_pixel == 24) {
167
                cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
168
                dst *= 3;
169
        }
170
 
171
        cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
172
        cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
173
        cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
174
        cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
175
}
176
 
177
static void
178
cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
179
{
180
        struct cfb_info *cfb = (struct cfb_info *)info;
181
        unsigned int cmd = CO_CMD_L_PATTERN_FGCOL;
182
        unsigned long src, dst;
183
 
184
        if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
185
                cfb_copyarea(info, region);
186
                return;
187
        }
188
 
189
        cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
190
        cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
191
        cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
192
 
193
        src = region->sx + region->sy * cfb->fb.var.xres_virtual;
194
        dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
195
 
196
        if (region->sx < region->dx) {
197
                src += region->width - 1;
198
                dst += region->width - 1;
199
                cmd |= CO_CMD_L_INC_LEFT;
200
        }
201
 
202
        if (region->sy < region->dy) {
203
                src += (region->height - 1) * cfb->fb.var.xres_virtual;
204
                dst += (region->height - 1) * cfb->fb.var.xres_virtual;
205
                cmd |= CO_CMD_L_INC_UP;
206
        }
207
 
208
        if (cfb->fb.var.bits_per_pixel == 24) {
209
                cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
210
                src *= 3;
211
                dst *= 3;
212
        }
213
        cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
214
        cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
215
        cyber2000fb_writew(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
216
        cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
217
        cyber2000fb_writew(CO_CMD_H_FGSRCMAP | CO_CMD_H_BLITTER,
218
                           CO_REG_CMD_H, cfb);
219
}
220
 
221
static void
222
cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image)
223
{
224
        cfb_imageblit(info, image);
225
        return;
226
}
227
 
228
static int cyber2000fb_sync(struct fb_info *info)
229
{
230
        struct cfb_info *cfb = (struct cfb_info *)info;
231
        int count = 100000;
232
 
233
        if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT))
234
                return 0;
235
 
236
        while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
237
                if (!count--) {
238
                        debug_printf("accel_wait timed out\n");
239
                        cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
240
                        break;
241
                }
242
                udelay(1);
243
        }
244
        return 0;
245
}
246
 
247
/*
248
 * ===========================================================================
249
 */
250
 
251
static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
252
{
253
        u_int mask = (1 << bf->length) - 1;
254
 
255
        return (val >> (16 - bf->length) & mask) << bf->offset;
256
}
257
 
258
/*
259
 *    Set a single color register. Return != 0 for invalid regno.
260
 */
261
static int
262
cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
263
                      u_int transp, struct fb_info *info)
264
{
265
        struct cfb_info *cfb = (struct cfb_info *)info;
266
        struct fb_var_screeninfo *var = &cfb->fb.var;
267
        u32 pseudo_val;
268
        int ret = 1;
269
 
270
        switch (cfb->fb.fix.visual) {
271
        default:
272
                return 1;
273
 
274
        /*
275
         * Pseudocolour:
276
         *         8     8
277
         * pixel --/--+--/-->  red lut  --> red dac
278
         *            |  8
279
         *            +--/--> green lut --> green dac
280
         *            |  8
281
         *            +--/-->  blue lut --> blue dac
282
         */
283
        case FB_VISUAL_PSEUDOCOLOR:
284
                if (regno >= NR_PALETTE)
285
                        return 1;
286
 
287
                red >>= 8;
288
                green >>= 8;
289
                blue >>= 8;
290
 
291
                cfb->palette[regno].red = red;
292
                cfb->palette[regno].green = green;
293
                cfb->palette[regno].blue = blue;
294
 
295
                cyber2000fb_writeb(regno, 0x3c8, cfb);
296
                cyber2000fb_writeb(red, 0x3c9, cfb);
297
                cyber2000fb_writeb(green, 0x3c9, cfb);
298
                cyber2000fb_writeb(blue, 0x3c9, cfb);
299
                return 0;
300
 
301
        /*
302
         * Direct colour:
303
         *         n     rl
304
         * pixel --/--+--/-->  red lut  --> red dac
305
         *            |  gl
306
         *            +--/--> green lut --> green dac
307
         *            |  bl
308
         *            +--/-->  blue lut --> blue dac
309
         * n = bpp, rl = red length, gl = green length, bl = blue length
310
         */
311
        case FB_VISUAL_DIRECTCOLOR:
312
                red >>= 8;
313
                green >>= 8;
314
                blue >>= 8;
315
 
316
                if (var->green.length == 6 && regno < 64) {
317
                        cfb->palette[regno << 2].green = green;
318
 
319
                        /*
320
                         * The 6 bits of the green component are applied
321
                         * to the high 6 bits of the LUT.
322
                         */
323
                        cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
324
                        cyber2000fb_writeb(cfb->palette[regno >> 1].red,
325
                                           0x3c9, cfb);
326
                        cyber2000fb_writeb(green, 0x3c9, cfb);
327
                        cyber2000fb_writeb(cfb->palette[regno >> 1].blue,
328
                                           0x3c9, cfb);
329
 
330
                        green = cfb->palette[regno << 3].green;
331
 
332
                        ret = 0;
333
                }
334
 
335
                if (var->green.length >= 5 && regno < 32) {
336
                        cfb->palette[regno << 3].red = red;
337
                        cfb->palette[regno << 3].green = green;
338
                        cfb->palette[regno << 3].blue = blue;
339
 
340
                        /*
341
                         * The 5 bits of each colour component are
342
                         * applied to the high 5 bits of the LUT.
343
                         */
344
                        cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
345
                        cyber2000fb_writeb(red, 0x3c9, cfb);
346
                        cyber2000fb_writeb(green, 0x3c9, cfb);
347
                        cyber2000fb_writeb(blue, 0x3c9, cfb);
348
                        ret = 0;
349
                }
350
 
351
                if (var->green.length == 4 && regno < 16) {
352
                        cfb->palette[regno << 4].red = red;
353
                        cfb->palette[regno << 4].green = green;
354
                        cfb->palette[regno << 4].blue = blue;
355
 
356
                        /*
357
                         * The 5 bits of each colour component are
358
                         * applied to the high 5 bits of the LUT.
359
                         */
360
                        cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
361
                        cyber2000fb_writeb(red, 0x3c9, cfb);
362
                        cyber2000fb_writeb(green, 0x3c9, cfb);
363
                        cyber2000fb_writeb(blue, 0x3c9, cfb);
364
                        ret = 0;
365
                }
366
 
367
                /*
368
                 * Since this is only used for the first 16 colours, we
369
                 * don't have to care about overflowing for regno >= 32
370
                 */
371
                pseudo_val = regno << var->red.offset |
372
                             regno << var->green.offset |
373
                             regno << var->blue.offset;
374
                break;
375
 
376
        /*
377
         * True colour:
378
         *         n     rl
379
         * pixel --/--+--/--> red dac
380
         *            |  gl
381
         *            +--/--> green dac
382
         *            |  bl
383
         *            +--/--> blue dac
384
         * n = bpp, rl = red length, gl = green length, bl = blue length
385
         */
386
        case FB_VISUAL_TRUECOLOR:
387
                pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
388
                pseudo_val |= convert_bitfield(red, &var->red);
389
                pseudo_val |= convert_bitfield(green, &var->green);
390
                pseudo_val |= convert_bitfield(blue, &var->blue);
391
                break;
392
        }
393
 
394
        /*
395
         * Now set our pseudo palette for the CFB16/24/32 drivers.
396
         */
397
        if (regno < 16)
398
                ((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
399
 
400
        return ret;
401
}
402
 
403
struct par_info {
404
        /*
405
         * Hardware
406
         */
407
        u_char  clock_mult;
408
        u_char  clock_div;
409
        u_char  extseqmisc;
410
        u_char  co_pixfmt;
411
        u_char  crtc_ofl;
412
        u_char  crtc[19];
413
        u_int   width;
414
        u_int   pitch;
415
        u_int   fetch;
416
 
417
        /*
418
         * Other
419
         */
420
        u_char  ramdac;
421
};
422
 
423
static const u_char crtc_idx[] = {
424
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
425
        0x08, 0x09,
426
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
427
};
428
 
429
static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
430
{
431
        unsigned int i;
432
        unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown;
433
 
434
        cyber2000fb_writeb(0x56, 0x3ce, cfb);
435
        i = cyber2000fb_readb(0x3cf, cfb);
436
        cyber2000fb_writeb(i | 4, 0x3cf, cfb);
437
        cyber2000fb_writeb(val, 0x3c6, cfb);
438
        cyber2000fb_writeb(i, 0x3cf, cfb);
439
}
440
 
441
static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
442
{
443
        u_int i;
444
 
445
        /*
446
         * Blank palette
447
         */
448
        for (i = 0; i < NR_PALETTE; i++) {
449
                cyber2000fb_writeb(i, 0x3c8, cfb);
450
                cyber2000fb_writeb(0, 0x3c9, cfb);
451
                cyber2000fb_writeb(0, 0x3c9, cfb);
452
                cyber2000fb_writeb(0, 0x3c9, cfb);
453
        }
454
 
455
        cyber2000fb_writeb(0xef, 0x3c2, cfb);
456
        cyber2000_crtcw(0x11, 0x0b, cfb);
457
        cyber2000_attrw(0x11, 0x00, cfb);
458
 
459
        cyber2000_seqw(0x00, 0x01, cfb);
460
        cyber2000_seqw(0x01, 0x01, cfb);
461
        cyber2000_seqw(0x02, 0x0f, cfb);
462
        cyber2000_seqw(0x03, 0x00, cfb);
463
        cyber2000_seqw(0x04, 0x0e, cfb);
464
        cyber2000_seqw(0x00, 0x03, cfb);
465
 
466
        for (i = 0; i < sizeof(crtc_idx); i++)
467
                cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb);
468
 
469
        for (i = 0x0a; i < 0x10; i++)
470
                cyber2000_crtcw(i, 0, cfb);
471
 
472
        cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb);
473
        cyber2000_grphw(0x00, 0x00, cfb);
474
        cyber2000_grphw(0x01, 0x00, cfb);
475
        cyber2000_grphw(0x02, 0x00, cfb);
476
        cyber2000_grphw(0x03, 0x00, cfb);
477
        cyber2000_grphw(0x04, 0x00, cfb);
478
        cyber2000_grphw(0x05, 0x60, cfb);
479
        cyber2000_grphw(0x06, 0x05, cfb);
480
        cyber2000_grphw(0x07, 0x0f, cfb);
481
        cyber2000_grphw(0x08, 0xff, cfb);
482
 
483
        /* Attribute controller registers */
484
        for (i = 0; i < 16; i++)
485
                cyber2000_attrw(i, i, cfb);
486
 
487
        cyber2000_attrw(0x10, 0x01, cfb);
488
        cyber2000_attrw(0x11, 0x00, cfb);
489
        cyber2000_attrw(0x12, 0x0f, cfb);
490
        cyber2000_attrw(0x13, 0x00, cfb);
491
        cyber2000_attrw(0x14, 0x00, cfb);
492
 
493
        /* PLL registers */
494
        cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
495
        cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
496
        cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
497
        cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb);
498
        cyber2000_grphw(0x90, 0x01, cfb);
499
        cyber2000_grphw(0xb9, 0x80, cfb);
500
        cyber2000_grphw(0xb9, 0x00, cfb);
501
 
502
        cfb->ramdac_ctrl = hw->ramdac;
503
        cyber2000fb_write_ramdac_ctrl(cfb);
504
 
505
        cyber2000fb_writeb(0x20, 0x3c0, cfb);
506
        cyber2000fb_writeb(0xff, 0x3c6, cfb);
507
 
508
        cyber2000_grphw(0x14, hw->fetch, cfb);
509
        cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
510
                              ((hw->pitch >> 4) & 0x30), cfb);
511
        cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);
512
 
513
        /*
514
         * Set up accelerator registers
515
         */
516
        cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
517
        cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
518
        cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
519
}
520
 
521
static inline int
522
cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
523
{
524
        u_int base = var->yoffset * var->xres_virtual + var->xoffset;
525
 
526
        base *= var->bits_per_pixel;
527
 
528
        /*
529
         * Convert to bytes and shift two extra bits because DAC
530
         * can only start on 4 byte aligned data.
531
         */
532
        base >>= 5;
533
 
534
        if (base >= 1 << 20)
535
                return -EINVAL;
536
 
537
        cyber2000_grphw(0x10, base >> 16 | 0x10, cfb);
538
        cyber2000_crtcw(0x0c, base >> 8, cfb);
539
        cyber2000_crtcw(0x0d, base, cfb);
540
 
541
        return 0;
542
}
543
 
544
static int
545
cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
546
                        struct fb_var_screeninfo *var)
547
{
548
        u_int Htotal, Hblankend, Hsyncend;
549
        u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
550
#define ENCODE_BIT(v, b1, m, b2) ((((v) >> (b1)) & (m)) << (b2))
551
 
552
        hw->crtc[13] = hw->pitch;
553
        hw->crtc[17] = 0xe3;
554
        hw->crtc[14] = 0;
555
        hw->crtc[8]  = 0;
556
 
557
        Htotal     = var->xres + var->right_margin +
558
                     var->hsync_len + var->left_margin;
559
 
560
        if (Htotal > 2080)
561
                return -EINVAL;
562
 
563
        hw->crtc[0] = (Htotal >> 3) - 5;
564
        hw->crtc[1] = (var->xres >> 3) - 1;
565
        hw->crtc[2] = var->xres >> 3;
566
        hw->crtc[4] = (var->xres + var->right_margin) >> 3;
567
 
568
        Hblankend   = (Htotal - 4 * 8) >> 3;
569
 
570
        hw->crtc[3] = ENCODE_BIT(Hblankend,  0, 0x1f,  0) |
571
                      ENCODE_BIT(1,          0, 0x01,  7);
572
 
573
        Hsyncend    = (var->xres + var->right_margin + var->hsync_len) >> 3;
574
 
575
        hw->crtc[5] = ENCODE_BIT(Hsyncend,   0, 0x1f,  0) |
576
                      ENCODE_BIT(Hblankend,  5, 0x01,  7);
577
 
578
        Vdispend    = var->yres - 1;
579
        Vsyncstart  = var->yres + var->lower_margin;
580
        Vsyncend    = var->yres + var->lower_margin + var->vsync_len;
581
        Vtotal      = var->yres + var->lower_margin + var->vsync_len +
582
                      var->upper_margin - 2;
583
 
584
        if (Vtotal > 2047)
585
                return -EINVAL;
586
 
587
        Vblankstart = var->yres + 6;
588
        Vblankend   = Vtotal - 10;
589
 
590
        hw->crtc[6]  = Vtotal;
591
        hw->crtc[7]  = ENCODE_BIT(Vtotal,     8, 0x01,  0) |
592
                        ENCODE_BIT(Vdispend,   8, 0x01,  1) |
593
                        ENCODE_BIT(Vsyncstart, 8, 0x01,  2) |
594
                        ENCODE_BIT(Vblankstart, 8, 0x01,  3) |
595
                        ENCODE_BIT(1,          0, 0x01,  4) |
596
                        ENCODE_BIT(Vtotal,     9, 0x01,  5) |
597
                        ENCODE_BIT(Vdispend,   9, 0x01,  6) |
598
                        ENCODE_BIT(Vsyncstart, 9, 0x01,  7);
599
        hw->crtc[9]  = ENCODE_BIT(0,          0, 0x1f,  0) |
600
                        ENCODE_BIT(Vblankstart, 9, 0x01,  5) |
601
                        ENCODE_BIT(1,          0, 0x01,  6);
602
        hw->crtc[10] = Vsyncstart;
603
        hw->crtc[11] = ENCODE_BIT(Vsyncend,   0, 0x0f,  0) |
604
                       ENCODE_BIT(1,          0, 0x01,  7);
605
        hw->crtc[12] = Vdispend;
606
        hw->crtc[15] = Vblankstart;
607
        hw->crtc[16] = Vblankend;
608
        hw->crtc[18] = 0xff;
609
 
610
        /*
611
         * overflow - graphics reg 0x11
612
         * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
613
         * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
614
         */
615
        hw->crtc_ofl =
616
                ENCODE_BIT(Vtotal, 10, 0x01, 0) |
617
                ENCODE_BIT(Vdispend, 10, 0x01, 1) |
618
                ENCODE_BIT(Vsyncstart, 10, 0x01, 2) |
619
                ENCODE_BIT(Vblankstart, 10, 0x01, 3) |
620
                EXT_CRT_VRTOFL_LINECOMP10;
621
 
622
        /* woody: set the interlaced bit... */
623
        /* FIXME: what about doublescan? */
624
        if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
625
                hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
626
 
627
        return 0;
628
}
629
 
630
/*
631
 * The following was discovered by a good monitor, bit twiddling, theorising
632
 * and but mostly luck.  Strangely, it looks like everyone elses' PLL!
633
 *
634
 * Clock registers:
635
 *   fclock = fpll / div2
636
 *   fpll   = fref * mult / div1
637
 * where:
638
 *   fref = 14.318MHz (69842ps)
639
 *   mult = reg0xb0.7:0
640
 *   div1 = (reg0xb1.5:0 + 1)
641
 *   div2 =  2^(reg0xb1.7:6)
642
 *   fpll should be between 115 and 260 MHz
643
 *  (8696ps and 3846ps)
644
 */
645
static int
646
cyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb,
647
                         struct fb_var_screeninfo *var)
648
{
649
        u_long pll_ps = var->pixclock;
650
        const u_long ref_ps = cfb->ref_ps;
651
        u_int div2, t_div1, best_div1, best_mult;
652
        int best_diff;
653
        int vco;
654
 
655
        /*
656
         * Step 1:
657
         *   find div2 such that 115MHz < fpll < 260MHz
658
         *   and 0 <= div2 < 4
659
         */
660
        for (div2 = 0; div2 < 4; div2++) {
661
                u_long new_pll;
662
 
663
                new_pll = pll_ps / cfb->divisors[div2];
664
                if (8696 > new_pll && new_pll > 3846) {
665
                        pll_ps = new_pll;
666
                        break;
667
                }
668
        }
669
 
670
        if (div2 == 4)
671
                return -EINVAL;
672
 
673
        /*
674
         * Step 2:
675
         *  Given pll_ps and ref_ps, find:
676
         *    pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005
677
         *  where { 1 < best_div1 < 32, 1 < best_mult < 256 }
678
         *    pll_ps_calc = best_div1 / (ref_ps * best_mult)
679
         */
680
        best_diff = 0x7fffffff;
681
        best_mult = 32;
682
        best_div1 = 255;
683
        for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) {
684
                u_int rr, t_mult, t_pll_ps;
685
                int diff;
686
 
687
                /*
688
                 * Find the multiplier for this divisor
689
                 */
690
                rr = ref_ps * t_div1;
691
                t_mult = (rr + pll_ps / 2) / pll_ps;
692
 
693
                /*
694
                 * Is the multiplier within the correct range?
695
                 */
696
                if (t_mult > 256 || t_mult < 2)
697
                        continue;
698
 
699
                /*
700
                 * Calculate the actual clock period from this multiplier
701
                 * and divisor, and estimate the error.
702
                 */
703
                t_pll_ps = (rr + t_mult / 2) / t_mult;
704
                diff = pll_ps - t_pll_ps;
705
                if (diff < 0)
706
                        diff = -diff;
707
 
708
                if (diff < best_diff) {
709
                        best_diff = diff;
710
                        best_mult = t_mult;
711
                        best_div1 = t_div1;
712
                }
713
 
714
                /*
715
                 * If we hit an exact value, there is no point in continuing.
716
                 */
717
                if (diff == 0)
718
                        break;
719
        }
720
 
721
        /*
722
         * Step 3:
723
         *  combine values
724
         */
725
        hw->clock_mult = best_mult - 1;
726
        hw->clock_div  = div2 << 6 | (best_div1 - 1);
727
 
728
        vco = ref_ps * best_div1 / best_mult;
729
        if ((ref_ps == 40690) && (vco < 5556))
730
                /* Set VFSEL when VCO > 180MHz (5.556 ps). */
731
                hw->clock_div |= EXT_DCLK_DIV_VFSEL;
732
 
733
        return 0;
734
}
735
 
736
/*
737
 *    Set the User Defined Part of the Display
738
 */
739
static int
740
cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
741
{
742
        struct cfb_info *cfb = (struct cfb_info *)info;
743
        struct par_info hw;
744
        unsigned int mem;
745
        int err;
746
 
747
        var->transp.msb_right   = 0;
748
        var->red.msb_right      = 0;
749
        var->green.msb_right    = 0;
750
        var->blue.msb_right     = 0;
751
        var->transp.offset      = 0;
752
        var->transp.length      = 0;
753
 
754
        switch (var->bits_per_pixel) {
755
        case 8: /* PSEUDOCOLOUR, 256 */
756
                var->red.offset         = 0;
757
                var->red.length         = 8;
758
                var->green.offset       = 0;
759
                var->green.length       = 8;
760
                var->blue.offset        = 0;
761
                var->blue.length        = 8;
762
                break;
763
 
764
        case 16:/* DIRECTCOLOUR, 64k or 32k */
765
                switch (var->green.length) {
766
                case 6: /* RGB565, 64k */
767
                        var->red.offset         = 11;
768
                        var->red.length         = 5;
769
                        var->green.offset       = 5;
770
                        var->green.length       = 6;
771
                        var->blue.offset        = 0;
772
                        var->blue.length        = 5;
773
                        break;
774
 
775
                default:
776
                case 5: /* RGB555, 32k */
777
                        var->red.offset         = 10;
778
                        var->red.length         = 5;
779
                        var->green.offset       = 5;
780
                        var->green.length       = 5;
781
                        var->blue.offset        = 0;
782
                        var->blue.length        = 5;
783
                        break;
784
 
785
                case 4: /* RGB444, 4k + transparency? */
786
                        var->transp.offset      = 12;
787
                        var->transp.length      = 4;
788
                        var->red.offset         = 8;
789
                        var->red.length         = 4;
790
                        var->green.offset       = 4;
791
                        var->green.length       = 4;
792
                        var->blue.offset        = 0;
793
                        var->blue.length        = 4;
794
                        break;
795
                }
796
                break;
797
 
798
        case 24:/* TRUECOLOUR, 16m */
799
                var->red.offset         = 16;
800
                var->red.length         = 8;
801
                var->green.offset       = 8;
802
                var->green.length       = 8;
803
                var->blue.offset        = 0;
804
                var->blue.length        = 8;
805
                break;
806
 
807
        case 32:/* TRUECOLOUR, 16m */
808
                var->transp.offset      = 24;
809
                var->transp.length      = 8;
810
                var->red.offset         = 16;
811
                var->red.length         = 8;
812
                var->green.offset       = 8;
813
                var->green.length       = 8;
814
                var->blue.offset        = 0;
815
                var->blue.length        = 8;
816
                break;
817
 
818
        default:
819
                return -EINVAL;
820
        }
821
 
822
        mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
823
        if (mem > cfb->fb.fix.smem_len)
824
                var->yres_virtual = cfb->fb.fix.smem_len * 8 /
825
                                    (var->bits_per_pixel * var->xres_virtual);
826
 
827
        if (var->yres > var->yres_virtual)
828
                var->yres = var->yres_virtual;
829
        if (var->xres > var->xres_virtual)
830
                var->xres = var->xres_virtual;
831
 
832
        err = cyber2000fb_decode_clock(&hw, cfb, var);
833
        if (err)
834
                return err;
835
 
836
        err = cyber2000fb_decode_crtc(&hw, cfb, var);
837
        if (err)
838
                return err;
839
 
840
        return 0;
841
}
842
 
843
static int cyber2000fb_set_par(struct fb_info *info)
844
{
845
        struct cfb_info *cfb = (struct cfb_info *)info;
846
        struct fb_var_screeninfo *var = &cfb->fb.var;
847
        struct par_info hw;
848
        unsigned int mem;
849
 
850
        hw.width = var->xres_virtual;
851
        hw.ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
852
 
853
        switch (var->bits_per_pixel) {
854
        case 8:
855
                hw.co_pixfmt            = CO_PIXFMT_8BPP;
856
                hw.pitch                = hw.width >> 3;
857
                hw.extseqmisc           = EXT_SEQ_MISC_8;
858
                break;
859
 
860
        case 16:
861
                hw.co_pixfmt            = CO_PIXFMT_16BPP;
862
                hw.pitch                = hw.width >> 2;
863
 
864
                switch (var->green.length) {
865
                case 6: /* RGB565, 64k */
866
                        hw.extseqmisc   = EXT_SEQ_MISC_16_RGB565;
867
                        break;
868
                case 5: /* RGB555, 32k */
869
                        hw.extseqmisc   = EXT_SEQ_MISC_16_RGB555;
870
                        break;
871
                case 4: /* RGB444, 4k + transparency? */
872
                        hw.extseqmisc   = EXT_SEQ_MISC_16_RGB444;
873
                        break;
874
                default:
875
                        BUG();
876
                }
877
                break;
878
 
879
        case 24:/* TRUECOLOUR, 16m */
880
                hw.co_pixfmt            = CO_PIXFMT_24BPP;
881
                hw.width                *= 3;
882
                hw.pitch                = hw.width >> 3;
883
                hw.ramdac               |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
884
                hw.extseqmisc           = EXT_SEQ_MISC_24_RGB888;
885
                break;
886
 
887
        case 32:/* TRUECOLOUR, 16m */
888
                hw.co_pixfmt            = CO_PIXFMT_32BPP;
889
                hw.pitch                = hw.width >> 1;
890
                hw.ramdac               |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
891
                hw.extseqmisc           = EXT_SEQ_MISC_32;
892
                break;
893
 
894
        default:
895
                BUG();
896
        }
897
 
898
        /*
899
         * Sigh, this is absolutely disgusting, but caused by
900
         * the way the fbcon developers want to separate out
901
         * the "checking" and the "setting" of the video mode.
902
         *
903
         * If the mode is not suitable for the hardware here,
904
         * we can't prevent it being set by returning an error.
905
         *
906
         * In theory, since NetWinders contain just one VGA card,
907
         * we should never end up hitting this problem.
908
         */
909
        BUG_ON(cyber2000fb_decode_clock(&hw, cfb, var) != 0);
910
        BUG_ON(cyber2000fb_decode_crtc(&hw, cfb, var) != 0);
911
 
912
        hw.width -= 1;
913
        hw.fetch = hw.pitch;
914
        if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT))
915
                hw.fetch <<= 1;
916
        hw.fetch += 1;
917
 
918
        cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
919
 
920
        /*
921
         * Same here - if the size of the video mode exceeds the
922
         * available RAM, we can't prevent this mode being set.
923
         *
924
         * In theory, since NetWinders contain just one VGA card,
925
         * we should never end up hitting this problem.
926
         */
927
        mem = cfb->fb.fix.line_length * var->yres_virtual;
928
        BUG_ON(mem > cfb->fb.fix.smem_len);
929
 
930
        /*
931
         * 8bpp displays are always pseudo colour.  16bpp and above
932
         * are direct colour or true colour, depending on whether
933
         * the RAMDAC palettes are bypassed.  (Direct colour has
934
         * palettes, true colour does not.)
935
         */
936
        if (var->bits_per_pixel == 8)
937
                cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
938
        else if (hw.ramdac & RAMDAC_BYPASS)
939
                cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
940
        else
941
                cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
942
 
943
        cyber2000fb_set_timing(cfb, &hw);
944
        cyber2000fb_update_start(cfb, var);
945
 
946
        return 0;
947
}
948
 
949
/*
950
 *    Pan or Wrap the Display
951
 */
952
static int
953
cyber2000fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
954
{
955
        struct cfb_info *cfb = (struct cfb_info *)info;
956
 
957
        if (cyber2000fb_update_start(cfb, var))
958
                return -EINVAL;
959
 
960
        cfb->fb.var.xoffset = var->xoffset;
961
        cfb->fb.var.yoffset = var->yoffset;
962
 
963
        if (var->vmode & FB_VMODE_YWRAP) {
964
                cfb->fb.var.vmode |= FB_VMODE_YWRAP;
965
        } else {
966
                cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
967
        }
968
 
969
        return 0;
970
}
971
 
972
/*
973
 *    (Un)Blank the display.
974
 *
975
 *  Blank the screen if blank_mode != 0, else unblank. If
976
 *  blank == NULL then the caller blanks by setting the CLUT
977
 *  (Color Look Up Table) to all black. Return 0 if blanking
978
 *  succeeded, != 0 if un-/blanking failed due to e.g. a
979
 *  video mode which doesn't support it. Implements VESA
980
 *  suspend and powerdown modes on hardware that supports
981
 *  disabling hsync/vsync:
982
 *    blank_mode == 2: suspend vsync
983
 *    blank_mode == 3: suspend hsync
984
 *    blank_mode == 4: powerdown
985
 *
986
 *  wms...Enable VESA DMPS compatible powerdown mode
987
 *  run "setterm -powersave powerdown" to take advantage
988
 */
989
static int cyber2000fb_blank(int blank, struct fb_info *info)
990
{
991
        struct cfb_info *cfb = (struct cfb_info *)info;
992
        unsigned int sync = 0;
993
        int i;
994
 
995
        switch (blank) {
996
        case FB_BLANK_POWERDOWN:        /* powerdown - both sync lines down */
997
                sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
998
                break;
999
        case FB_BLANK_HSYNC_SUSPEND:    /* hsync off */
1000
                sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;
1001
                break;
1002
        case FB_BLANK_VSYNC_SUSPEND:    /* vsync off */
1003
                sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
1004
                break;
1005
        case FB_BLANK_NORMAL:           /* soft blank */
1006
        default:                        /* unblank */
1007
                break;
1008
        }
1009
 
1010
        cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
1011
 
1012
        if (blank <= 1) {
1013
                /* turn on ramdacs */
1014
                cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS |
1015
                                           RAMDAC_RAMPWRDN);
1016
                cyber2000fb_write_ramdac_ctrl(cfb);
1017
        }
1018
 
1019
        /*
1020
         * Soft blank/unblank the display.
1021
         */
1022
        if (blank) {    /* soft blank */
1023
                for (i = 0; i < NR_PALETTE; i++) {
1024
                        cyber2000fb_writeb(i, 0x3c8, cfb);
1025
                        cyber2000fb_writeb(0, 0x3c9, cfb);
1026
                        cyber2000fb_writeb(0, 0x3c9, cfb);
1027
                        cyber2000fb_writeb(0, 0x3c9, cfb);
1028
                }
1029
        } else {        /* unblank */
1030
                for (i = 0; i < NR_PALETTE; i++) {
1031
                        cyber2000fb_writeb(i, 0x3c8, cfb);
1032
                        cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
1033
                        cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
1034
                        cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
1035
                }
1036
        }
1037
 
1038
        if (blank >= 2) {
1039
                /* turn off ramdacs */
1040
                cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS |
1041
                                         RAMDAC_RAMPWRDN;
1042
                cyber2000fb_write_ramdac_ctrl(cfb);
1043
        }
1044
 
1045
        return 0;
1046
}
1047
 
1048
static struct fb_ops cyber2000fb_ops = {
1049
        .owner          = THIS_MODULE,
1050
        .fb_check_var   = cyber2000fb_check_var,
1051
        .fb_set_par     = cyber2000fb_set_par,
1052
        .fb_setcolreg   = cyber2000fb_setcolreg,
1053
        .fb_blank       = cyber2000fb_blank,
1054
        .fb_pan_display = cyber2000fb_pan_display,
1055
        .fb_fillrect    = cyber2000fb_fillrect,
1056
        .fb_copyarea    = cyber2000fb_copyarea,
1057
        .fb_imageblit   = cyber2000fb_imageblit,
1058
        .fb_sync        = cyber2000fb_sync,
1059
};
1060
 
1061
/*
1062
 * This is the only "static" reference to the internal data structures
1063
 * of this driver.  It is here solely at the moment to support the other
1064
 * CyberPro modules external to this driver.
1065
 */
1066
static struct cfb_info *int_cfb_info;
1067
 
1068
/*
1069
 * Enable access to the extended registers
1070
 */
1071
void cyber2000fb_enable_extregs(struct cfb_info *cfb)
1072
{
1073
        cfb->func_use_count += 1;
1074
 
1075
        if (cfb->func_use_count == 1) {
1076
                int old;
1077
 
1078
                old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
1079
                old |= EXT_FUNC_CTL_EXTREGENBL;
1080
                cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
1081
        }
1082
}
1083
EXPORT_SYMBOL(cyber2000fb_enable_extregs);
1084
 
1085
/*
1086
 * Disable access to the extended registers
1087
 */
1088
void cyber2000fb_disable_extregs(struct cfb_info *cfb)
1089
{
1090
        if (cfb->func_use_count == 1) {
1091
                int old;
1092
 
1093
                old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
1094
                old &= ~EXT_FUNC_CTL_EXTREGENBL;
1095
                cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
1096
        }
1097
 
1098
        if (cfb->func_use_count == 0)
1099
                printk(KERN_ERR "disable_extregs: count = 0\n");
1100
        else
1101
                cfb->func_use_count -= 1;
1102
}
1103
EXPORT_SYMBOL(cyber2000fb_disable_extregs);
1104
 
1105
void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
1106
{
1107
        memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo));
1108
}
1109
EXPORT_SYMBOL(cyber2000fb_get_fb_var);
1110
 
1111
/*
1112
 * Attach a capture/tv driver to the core CyberX0X0 driver.
1113
 */
1114
int cyber2000fb_attach(struct cyberpro_info *info, int idx)
1115
{
1116
        if (int_cfb_info != NULL) {
1117
                info->dev             = int_cfb_info->dev;
1118
                info->regs            = int_cfb_info->regs;
1119
                info->fb              = int_cfb_info->fb.screen_base;
1120
                info->fb_size         = int_cfb_info->fb.fix.smem_len;
1121
                info->enable_extregs  = cyber2000fb_enable_extregs;
1122
                info->disable_extregs = cyber2000fb_disable_extregs;
1123
                info->info            = int_cfb_info;
1124
 
1125
                strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
1126
                        sizeof(info->dev_name));
1127
        }
1128
 
1129
        return int_cfb_info != NULL;
1130
}
1131
EXPORT_SYMBOL(cyber2000fb_attach);
1132
 
1133
/*
1134
 * Detach a capture/tv driver from the core CyberX0X0 driver.
1135
 */
1136
void cyber2000fb_detach(int idx)
1137
{
1138
}
1139
EXPORT_SYMBOL(cyber2000fb_detach);
1140
 
1141
/*
1142
 * These parameters give
1143
 * 640x480, hsync 31.5kHz, vsync 60Hz
1144
 */
1145
static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
1146
        .refresh        = 60,
1147
        .xres           = 640,
1148
        .yres           = 480,
1149
        .pixclock       = 39722,
1150
        .left_margin    = 56,
1151
        .right_margin   = 16,
1152
        .upper_margin   = 34,
1153
        .lower_margin   = 9,
1154
        .hsync_len      = 88,
1155
        .vsync_len      = 2,
1156
        .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1157
        .vmode          = FB_VMODE_NONINTERLACED
1158
};
1159
 
1160
static char igs_regs[] = {
1161
        EXT_CRT_IRQ,            0,
1162
        EXT_CRT_TEST,           0,
1163
        EXT_SYNC_CTL,           0,
1164
        EXT_SEG_WRITE_PTR,      0,
1165
        EXT_SEG_READ_PTR,       0,
1166
        EXT_BIU_MISC,           EXT_BIU_MISC_LIN_ENABLE |
1167
                                EXT_BIU_MISC_COP_ENABLE |
1168
                                EXT_BIU_MISC_COP_BFC,
1169
        EXT_FUNC_CTL,           0,
1170
        CURS_H_START,           0,
1171
        CURS_H_START + 1,       0,
1172
        CURS_H_PRESET,          0,
1173
        CURS_V_START,           0,
1174
        CURS_V_START + 1,       0,
1175
        CURS_V_PRESET,          0,
1176
        CURS_CTL,               0,
1177
        EXT_ATTRIB_CTL,         EXT_ATTRIB_CTL_EXT,
1178
        EXT_OVERSCAN_RED,       0,
1179
        EXT_OVERSCAN_GREEN,     0,
1180
        EXT_OVERSCAN_BLUE,      0,
1181
 
1182
        /* some of these are questionable when we have a BIOS */
1183
        EXT_MEM_CTL0,           EXT_MEM_CTL0_7CLK |
1184
                                EXT_MEM_CTL0_RAS_1 |
1185
                                EXT_MEM_CTL0_MULTCAS,
1186
        EXT_HIDDEN_CTL1,        0x30,
1187
        EXT_FIFO_CTL,           0x0b,
1188
        EXT_FIFO_CTL + 1,       0x17,
1189
        0x76,                   0x00,
1190
        EXT_HIDDEN_CTL4,        0xc8
1191
};
1192
 
1193
/*
1194
 * Initialise the CyberPro hardware.  On the CyberPro5XXXX,
1195
 * ensure that we're using the correct PLL (5XXX's may be
1196
 * programmed to use an additional set of PLLs.)
1197
 */
1198
static void cyberpro_init_hw(struct cfb_info *cfb)
1199
{
1200
        int i;
1201
 
1202
        for (i = 0; i < sizeof(igs_regs); i += 2)
1203
                cyber2000_grphw(igs_regs[i], igs_regs[i + 1], cfb);
1204
 
1205
        if (cfb->id == ID_CYBERPRO_5000) {
1206
                unsigned char val;
1207
                cyber2000fb_writeb(0xba, 0x3ce, cfb);
1208
                val = cyber2000fb_readb(0x3cf, cfb) & 0x80;
1209
                cyber2000fb_writeb(val, 0x3cf, cfb);
1210
        }
1211
}
1212
 
1213
static struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id,
1214
                                                         char *name)
1215
{
1216
        struct cfb_info *cfb;
1217
 
1218
        cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
1219
        if (!cfb)
1220
                return NULL;
1221
 
1222
 
1223
        cfb->id                 = id;
1224
 
1225
        if (id == ID_CYBERPRO_5000)
1226
                cfb->ref_ps     = 40690; /* 24.576 MHz */
1227
        else
1228
                cfb->ref_ps     = 69842; /* 14.31818 MHz (69841?) */
1229
 
1230
        cfb->divisors[0] = 1;
1231
        cfb->divisors[1]        = 2;
1232
        cfb->divisors[2]        = 4;
1233
 
1234
        if (id == ID_CYBERPRO_2000)
1235
                cfb->divisors[3] = 8;
1236
        else
1237
                cfb->divisors[3] = 6;
1238
 
1239
        strcpy(cfb->fb.fix.id, name);
1240
 
1241
        cfb->fb.fix.type        = FB_TYPE_PACKED_PIXELS;
1242
        cfb->fb.fix.type_aux    = 0;
1243
        cfb->fb.fix.xpanstep    = 0;
1244
        cfb->fb.fix.ypanstep    = 1;
1245
        cfb->fb.fix.ywrapstep   = 0;
1246
 
1247
        switch (id) {
1248
        case ID_IGA_1682:
1249
                cfb->fb.fix.accel = 0;
1250
                break;
1251
 
1252
        case ID_CYBERPRO_2000:
1253
                cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000;
1254
                break;
1255
 
1256
        case ID_CYBERPRO_2010:
1257
                cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010;
1258
                break;
1259
 
1260
        case ID_CYBERPRO_5000:
1261
                cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000;
1262
                break;
1263
        }
1264
 
1265
        cfb->fb.var.nonstd      = 0;
1266
        cfb->fb.var.activate    = FB_ACTIVATE_NOW;
1267
        cfb->fb.var.height      = -1;
1268
        cfb->fb.var.width       = -1;
1269
        cfb->fb.var.accel_flags = FB_ACCELF_TEXT;
1270
 
1271
        cfb->fb.fbops           = &cyber2000fb_ops;
1272
        cfb->fb.flags           = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1273
        cfb->fb.pseudo_palette  = cfb->pseudo_palette;
1274
 
1275
        fb_alloc_cmap(&cfb->fb.cmap, NR_PALETTE, 0);
1276
 
1277
        return cfb;
1278
}
1279
 
1280
static void cyberpro_free_fb_info(struct cfb_info *cfb)
1281
{
1282
        if (cfb) {
1283
                /*
1284
                 * Free the colourmap
1285
                 */
1286
                fb_alloc_cmap(&cfb->fb.cmap, 0, 0);
1287
 
1288
                kfree(cfb);
1289
        }
1290
}
1291
 
1292
/*
1293
 * Parse Cyber2000fb options.  Usage:
1294
 *  video=cyber2000:font:fontname
1295
 */
1296
#ifndef MODULE
1297
static int cyber2000fb_setup(char *options)
1298
{
1299
        char *opt;
1300
 
1301
        if (!options || !*options)
1302
                return 0;
1303
 
1304
        while ((opt = strsep(&options, ",")) != NULL) {
1305
                if (!*opt)
1306
                        continue;
1307
 
1308
                if (strncmp(opt, "font:", 5) == 0) {
1309
                        static char default_font_storage[40];
1310
 
1311
                        strlcpy(default_font_storage, opt + 5,
1312
                                sizeof(default_font_storage));
1313
                        default_font = default_font_storage;
1314
                        continue;
1315
                }
1316
 
1317
                printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n", opt);
1318
        }
1319
        return 0;
1320
}
1321
#endif  /*  MODULE  */
1322
 
1323
/*
1324
 * The CyberPro chips can be placed on many different bus types.
1325
 * This probe function is common to all bus types.  The bus-specific
1326
 * probe function is expected to have:
1327
 *  - enabled access to the linear memory region
1328
 *  - memory mapped access to the registers
1329
 *  - initialised mem_ctl1 and mem_ctl2 appropriately.
1330
 */
1331
static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
1332
{
1333
        u_long smem_size;
1334
        u_int h_sync, v_sync;
1335
        int err;
1336
 
1337
        cyberpro_init_hw(cfb);
1338
 
1339
        /*
1340
         * Get the video RAM size and width from the VGA register.
1341
         * This should have been already initialised by the BIOS,
1342
         * but if it's garbage, claim default 1MB VRAM (woody)
1343
         */
1344
        cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb);
1345
        cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb);
1346
 
1347
        /*
1348
         * Determine the size of the memory.
1349
         */
1350
        switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
1351
        case MEM_CTL2_SIZE_4MB:
1352
                smem_size = 0x00400000;
1353
                break;
1354
        case MEM_CTL2_SIZE_2MB:
1355
                smem_size = 0x00200000;
1356
                break;
1357
        case MEM_CTL2_SIZE_1MB:
1358
                smem_size = 0x00100000;
1359
                break;
1360
        default:
1361
                smem_size = 0x00100000;
1362
                break;
1363
        }
1364
 
1365
        cfb->fb.fix.smem_len   = smem_size;
1366
        cfb->fb.fix.mmio_len   = MMIO_SIZE;
1367
        cfb->fb.screen_base    = cfb->region;
1368
 
1369
        err = -EINVAL;
1370
        if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
1371
                          &cyber2000fb_default_mode, 8)) {
1372
                printk(KERN_ERR "%s: no valid mode found\n", cfb->fb.fix.id);
1373
                goto failed;
1374
        }
1375
 
1376
        cfb->fb.var.yres_virtual = cfb->fb.fix.smem_len * 8 /
1377
                        (cfb->fb.var.bits_per_pixel * cfb->fb.var.xres_virtual);
1378
 
1379
        if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
1380
                cfb->fb.var.yres_virtual = cfb->fb.var.yres;
1381
 
1382
/*      fb_set_var(&cfb->fb.var, -1, &cfb->fb); */
1383
 
1384
        /*
1385
         * Calculate the hsync and vsync frequencies.  Note that
1386
         * we split the 1e12 constant up so that we can preserve
1387
         * the precision and fit the results into 32-bit registers.
1388
         *  (1953125000 * 512 = 1e12)
1389
         */
1390
        h_sync = 1953125000 / cfb->fb.var.pixclock;
1391
        h_sync = h_sync * 512 / (cfb->fb.var.xres + cfb->fb.var.left_margin +
1392
                 cfb->fb.var.right_margin + cfb->fb.var.hsync_len);
1393
        v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
1394
                 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
1395
 
1396
        printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
1397
                cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
1398
                cfb->fb.var.xres, cfb->fb.var.yres,
1399
                h_sync / 1000, h_sync % 1000, v_sync);
1400
 
1401
        if (cfb->dev)
1402
                cfb->fb.device = &cfb->dev->dev;
1403
        err = register_framebuffer(&cfb->fb);
1404
 
1405
failed:
1406
        return err;
1407
}
1408
 
1409
static void cyberpro_common_resume(struct cfb_info *cfb)
1410
{
1411
        cyberpro_init_hw(cfb);
1412
 
1413
        /*
1414
         * Reprogram the MEM_CTL1 and MEM_CTL2 registers
1415
         */
1416
        cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb);
1417
        cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb);
1418
 
1419
        /*
1420
         * Restore the old video mode and the palette.
1421
         * We also need to tell fbcon to redraw the console.
1422
         */
1423
        cyber2000fb_set_par(&cfb->fb);
1424
}
1425
 
1426
#ifdef CONFIG_ARCH_SHARK
1427
 
1428
#include <asm/arch/hardware.h>
1429
 
1430
static int __devinit cyberpro_vl_probe(void)
1431
{
1432
        struct cfb_info *cfb;
1433
        int err = -ENOMEM;
1434
 
1435
        if (!request_mem_region(FB_START, FB_SIZE, "CyberPro2010"))
1436
                return err;
1437
 
1438
        cfb = cyberpro_alloc_fb_info(ID_CYBERPRO_2010, "CyberPro2010");
1439
        if (!cfb)
1440
                goto failed_release;
1441
 
1442
        cfb->dev = NULL;
1443
        cfb->region = ioremap(FB_START, FB_SIZE);
1444
        if (!cfb->region)
1445
                goto failed_ioremap;
1446
 
1447
        cfb->regs = cfb->region + MMIO_OFFSET;
1448
        cfb->fb.fix.mmio_start = FB_START + MMIO_OFFSET;
1449
        cfb->fb.fix.smem_start = FB_START;
1450
 
1451
        /*
1452
         * Bring up the hardware.  This is expected to enable access
1453
         * to the linear memory region, and allow access to the memory
1454
         * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
1455
         * initialised.
1456
         */
1457
        cyber2000fb_writeb(0x18, 0x46e8, cfb);
1458
        cyber2000fb_writeb(0x01, 0x102, cfb);
1459
        cyber2000fb_writeb(0x08, 0x46e8, cfb);
1460
        cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb);
1461
        cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb);
1462
 
1463
        cfb->mclk_mult = 0xdb;
1464
        cfb->mclk_div  = 0x54;
1465
 
1466
        err = cyberpro_common_probe(cfb);
1467
        if (err)
1468
                goto failed;
1469
 
1470
        if (int_cfb_info == NULL)
1471
                int_cfb_info = cfb;
1472
 
1473
        return 0;
1474
 
1475
failed:
1476
        iounmap(cfb->region);
1477
failed_ioremap:
1478
        cyberpro_free_fb_info(cfb);
1479
failed_release:
1480
        release_mem_region(FB_START, FB_SIZE);
1481
 
1482
        return err;
1483
}
1484
#endif /* CONFIG_ARCH_SHARK */
1485
 
1486
/*
1487
 * PCI specific support.
1488
 */
1489
#ifdef CONFIG_PCI
1490
/*
1491
 * We need to wake up the CyberPro, and make sure its in linear memory
1492
 * mode.  Unfortunately, this is specific to the platform and card that
1493
 * we are running on.
1494
 *
1495
 * On x86 and ARM, should we be initialising the CyberPro first via the
1496
 * IO registers, and then the MMIO registers to catch all cases?  Can we
1497
 * end up in the situation where the chip is in MMIO mode, but not awake
1498
 * on an x86 system?
1499
 */
1500
static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
1501
{
1502
        unsigned char val;
1503
 
1504
#if defined(__sparc_v9__)
1505
#error "You lose, consult DaveM."
1506
#elif defined(__sparc__)
1507
        /*
1508
         * SPARC does not have an "outb" instruction, so we generate
1509
         * I/O cycles storing into a reserved memory space at
1510
         * physical address 0x3000000
1511
         */
1512
        unsigned char __iomem *iop;
1513
 
1514
        iop = ioremap(0x3000000, 0x5000);
1515
        if (iop == NULL) {
1516
                prom_printf("iga5000: cannot map I/O\n");
1517
                return -ENOMEM;
1518
        }
1519
 
1520
        writeb(0x18, iop + 0x46e8);
1521
        writeb(0x01, iop + 0x102);
1522
        writeb(0x08, iop + 0x46e8);
1523
        writeb(EXT_BIU_MISC, iop + 0x3ce);
1524
        writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf);
1525
 
1526
        iounmap(iop);
1527
#else
1528
        /*
1529
         * Most other machine types are "normal", so
1530
         * we use the standard IO-based wakeup.
1531
         */
1532
        outb(0x18, 0x46e8);
1533
        outb(0x01, 0x102);
1534
        outb(0x08, 0x46e8);
1535
        outb(EXT_BIU_MISC, 0x3ce);
1536
        outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);
1537
#endif
1538
 
1539
        /*
1540
         * Allow the CyberPro to accept PCI burst accesses
1541
         */
1542
        if (cfb->id == ID_CYBERPRO_2010) {
1543
                printk(KERN_INFO "%s: NOT enabling PCI bursts\n",
1544
                       cfb->fb.fix.id);
1545
        } else {
1546
                val = cyber2000_grphr(EXT_BUS_CTL, cfb);
1547
                if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
1548
                        printk(KERN_INFO "%s: enabling PCI bursts\n",
1549
                                cfb->fb.fix.id);
1550
 
1551
                        val |= EXT_BUS_CTL_PCIBURST_WRITE;
1552
 
1553
                        if (cfb->id == ID_CYBERPRO_5000)
1554
                                val |= EXT_BUS_CTL_PCIBURST_READ;
1555
 
1556
                        cyber2000_grphw(EXT_BUS_CTL, val, cfb);
1557
                }
1558
        }
1559
 
1560
        return 0;
1561
}
1562
 
1563
static int __devinit
1564
cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
1565
{
1566
        struct cfb_info *cfb;
1567
        char name[16];
1568
        int err;
1569
 
1570
        sprintf(name, "CyberPro%4X", id->device);
1571
 
1572
        err = pci_enable_device(dev);
1573
        if (err)
1574
                return err;
1575
 
1576
        err = pci_request_regions(dev, name);
1577
        if (err)
1578
                return err;
1579
 
1580
        err = -ENOMEM;
1581
        cfb = cyberpro_alloc_fb_info(id->driver_data, name);
1582
        if (!cfb)
1583
                goto failed_release;
1584
 
1585
        cfb->dev = dev;
1586
        cfb->region = ioremap(pci_resource_start(dev, 0),
1587
                              pci_resource_len(dev, 0));
1588
        if (!cfb->region)
1589
                goto failed_ioremap;
1590
 
1591
        cfb->regs = cfb->region + MMIO_OFFSET;
1592
        cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
1593
        cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
1594
 
1595
        /*
1596
         * Bring up the hardware.  This is expected to enable access
1597
         * to the linear memory region, and allow access to the memory
1598
         * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
1599
         * initialised.
1600
         */
1601
        err = cyberpro_pci_enable_mmio(cfb);
1602
        if (err)
1603
                goto failed;
1604
 
1605
        /*
1606
         * Use MCLK from BIOS. FIXME: what about hotplug?
1607
         */
1608
        cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
1609
        cfb->mclk_div  = cyber2000_grphr(EXT_MCLK_DIV, cfb);
1610
 
1611
#ifdef __arm__
1612
        /*
1613
         * MCLK on the NetWinder and the Shark is fixed at 75MHz
1614
         */
1615
        if (machine_is_netwinder()) {
1616
                cfb->mclk_mult = 0xdb;
1617
                cfb->mclk_div  = 0x54;
1618
        }
1619
#endif
1620
 
1621
        err = cyberpro_common_probe(cfb);
1622
        if (err)
1623
                goto failed;
1624
 
1625
        /*
1626
         * Our driver data
1627
         */
1628
        pci_set_drvdata(dev, cfb);
1629
        if (int_cfb_info == NULL)
1630
                int_cfb_info = cfb;
1631
 
1632
        return 0;
1633
 
1634
failed:
1635
        iounmap(cfb->region);
1636
failed_ioremap:
1637
        cyberpro_free_fb_info(cfb);
1638
failed_release:
1639
        pci_release_regions(dev);
1640
 
1641
        return err;
1642
}
1643
 
1644
static void __devexit cyberpro_pci_remove(struct pci_dev *dev)
1645
{
1646
        struct cfb_info *cfb = pci_get_drvdata(dev);
1647
 
1648
        if (cfb) {
1649
                /*
1650
                 * If unregister_framebuffer fails, then
1651
                 * we will be leaving hooks that could cause
1652
                 * oopsen laying around.
1653
                 */
1654
                if (unregister_framebuffer(&cfb->fb))
1655
                        printk(KERN_WARNING "%s: danger Will Robinson, "
1656
                                "danger danger!  Oopsen imminent!\n",
1657
                                cfb->fb.fix.id);
1658
                iounmap(cfb->region);
1659
                cyberpro_free_fb_info(cfb);
1660
 
1661
                /*
1662
                 * Ensure that the driver data is no longer
1663
                 * valid.
1664
                 */
1665
                pci_set_drvdata(dev, NULL);
1666
                if (cfb == int_cfb_info)
1667
                        int_cfb_info = NULL;
1668
 
1669
                pci_release_regions(dev);
1670
        }
1671
}
1672
 
1673
static int cyberpro_pci_suspend(struct pci_dev *dev, pm_message_t state)
1674
{
1675
        return 0;
1676
}
1677
 
1678
/*
1679
 * Re-initialise the CyberPro hardware
1680
 */
1681
static int cyberpro_pci_resume(struct pci_dev *dev)
1682
{
1683
        struct cfb_info *cfb = pci_get_drvdata(dev);
1684
 
1685
        if (cfb) {
1686
                cyberpro_pci_enable_mmio(cfb);
1687
                cyberpro_common_resume(cfb);
1688
        }
1689
 
1690
        return 0;
1691
}
1692
 
1693
static struct pci_device_id cyberpro_pci_table[] = {
1694
/*      Not yet
1695
 *      { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
1696
 *              PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
1697
 */
1698
        { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
1699
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
1700
        { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
1701
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 },
1702
        { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
1703
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 },
1704
        { 0, }
1705
};
1706
 
1707
MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
1708
 
1709
static struct pci_driver cyberpro_driver = {
1710
        .name           = "CyberPro",
1711
        .probe          = cyberpro_pci_probe,
1712
        .remove         = __devexit_p(cyberpro_pci_remove),
1713
        .suspend        = cyberpro_pci_suspend,
1714
        .resume         = cyberpro_pci_resume,
1715
        .id_table       = cyberpro_pci_table
1716
};
1717
#endif
1718
 
1719
/*
1720
 * I don't think we can use the "module_init" stuff here because
1721
 * the fbcon stuff may not be initialised yet.  Hence the #ifdef
1722
 * around module_init.
1723
 *
1724
 * Tony: "module_init" is now required
1725
 */
1726
static int __init cyber2000fb_init(void)
1727
{
1728
        int ret = -1, err;
1729
 
1730
#ifndef MODULE
1731
        char *option = NULL;
1732
 
1733
        if (fb_get_options("cyber2000fb", &option))
1734
                return -ENODEV;
1735
        cyber2000fb_setup(option);
1736
#endif
1737
 
1738
#ifdef CONFIG_ARCH_SHARK
1739
        err = cyberpro_vl_probe();
1740
        if (!err) {
1741
                ret = 0;
1742
                __module_get(THIS_MODULE);
1743
        }
1744
#endif
1745
#ifdef CONFIG_PCI
1746
        err = pci_register_driver(&cyberpro_driver);
1747
        if (!err)
1748
                ret = 0;
1749
#endif
1750
 
1751
        return ret ? err : 0;
1752
}
1753
 
1754
static void __exit cyberpro_exit(void)
1755
{
1756
        pci_unregister_driver(&cyberpro_driver);
1757
}
1758
 
1759
module_init(cyber2000fb_init);
1760
module_exit(cyberpro_exit);
1761
 
1762
MODULE_AUTHOR("Russell King");
1763
MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
1764
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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