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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver
2
 *
3
 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
4
 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
5
 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6
 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
7
 *
8
 * Driver layout based loosely on tgafb.c, see that file for credits.
9
 */
10
 
11
#include <linux/module.h>
12
#include <linux/kernel.h>
13
#include <linux/errno.h>
14
#include <linux/string.h>
15
#include <linux/slab.h>
16
#include <linux/delay.h>
17
#include <linux/init.h>
18
#include <linux/fb.h>
19
#include <linux/mm.h>
20
 
21
#include <asm/io.h>
22
#include <asm/of_device.h>
23
#include <asm/fbio.h>
24
 
25
#include "sbuslib.h"
26
 
27
/*
28
 * Local functions.
29
 */
30
 
31
static int cg6_setcolreg(unsigned, unsigned, unsigned, unsigned,
32
                         unsigned, struct fb_info *);
33
static int cg6_blank(int, struct fb_info *);
34
 
35
static void cg6_imageblit(struct fb_info *, const struct fb_image *);
36
static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
37
static int cg6_sync(struct fb_info *);
38
static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
39
static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
40
static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
41
 
42
/*
43
 *  Frame buffer operations
44
 */
45
 
46
static struct fb_ops cg6_ops = {
47
        .owner                  = THIS_MODULE,
48
        .fb_setcolreg           = cg6_setcolreg,
49
        .fb_blank               = cg6_blank,
50
        .fb_fillrect            = cg6_fillrect,
51
        .fb_copyarea            = cg6_copyarea,
52
        .fb_imageblit           = cg6_imageblit,
53
        .fb_sync                = cg6_sync,
54
        .fb_mmap                = cg6_mmap,
55
        .fb_ioctl               = cg6_ioctl,
56
#ifdef CONFIG_COMPAT
57
        .fb_compat_ioctl        = sbusfb_compat_ioctl,
58
#endif
59
};
60
 
61
/* Offset of interesting structures in the OBIO space */
62
/*
63
 * Brooktree is the video dac and is funny to program on the cg6.
64
 * (it's even funnier on the cg3)
65
 * The FBC could be the frame buffer control
66
 * The FHC could is the frame buffer hardware control.
67
 */
68
#define CG6_ROM_OFFSET                  0x0UL
69
#define CG6_BROOKTREE_OFFSET            0x200000UL
70
#define CG6_DHC_OFFSET                  0x240000UL
71
#define CG6_ALT_OFFSET                  0x280000UL
72
#define CG6_FHC_OFFSET                  0x300000UL
73
#define CG6_THC_OFFSET                  0x301000UL
74
#define CG6_FBC_OFFSET                  0x700000UL
75
#define CG6_TEC_OFFSET                  0x701000UL
76
#define CG6_RAM_OFFSET                  0x800000UL
77
 
78
/* FHC definitions */
79
#define CG6_FHC_FBID_SHIFT              24
80
#define CG6_FHC_FBID_MASK               255
81
#define CG6_FHC_REV_SHIFT               20
82
#define CG6_FHC_REV_MASK                15
83
#define CG6_FHC_FROP_DISABLE            (1 << 19)
84
#define CG6_FHC_ROW_DISABLE             (1 << 18)
85
#define CG6_FHC_SRC_DISABLE             (1 << 17)
86
#define CG6_FHC_DST_DISABLE             (1 << 16)
87
#define CG6_FHC_RESET                   (1 << 15)
88
#define CG6_FHC_LITTLE_ENDIAN           (1 << 13)
89
#define CG6_FHC_RES_MASK                (3 << 11)
90
#define CG6_FHC_1024                    (0 << 11)
91
#define CG6_FHC_1152                    (1 << 11)
92
#define CG6_FHC_1280                    (2 << 11)
93
#define CG6_FHC_1600                    (3 << 11)
94
#define CG6_FHC_CPU_MASK                (3 << 9)
95
#define CG6_FHC_CPU_SPARC               (0 << 9)
96
#define CG6_FHC_CPU_68020               (1 << 9)
97
#define CG6_FHC_CPU_386                 (2 << 9)
98
#define CG6_FHC_TEST                    (1 << 8)
99
#define CG6_FHC_TEST_X_SHIFT            4
100
#define CG6_FHC_TEST_X_MASK             15
101
#define CG6_FHC_TEST_Y_SHIFT            0
102
#define CG6_FHC_TEST_Y_MASK             15
103
 
104
/* FBC mode definitions */
105
#define CG6_FBC_BLIT_IGNORE             0x00000000
106
#define CG6_FBC_BLIT_NOSRC              0x00100000
107
#define CG6_FBC_BLIT_SRC                0x00200000
108
#define CG6_FBC_BLIT_ILLEGAL            0x00300000
109
#define CG6_FBC_BLIT_MASK               0x00300000
110
 
111
#define CG6_FBC_VBLANK                  0x00080000
112
 
113
#define CG6_FBC_MODE_IGNORE             0x00000000
114
#define CG6_FBC_MODE_COLOR8             0x00020000
115
#define CG6_FBC_MODE_COLOR1             0x00040000
116
#define CG6_FBC_MODE_HRMONO             0x00060000
117
#define CG6_FBC_MODE_MASK               0x00060000
118
 
119
#define CG6_FBC_DRAW_IGNORE             0x00000000
120
#define CG6_FBC_DRAW_RENDER             0x00008000
121
#define CG6_FBC_DRAW_PICK               0x00010000
122
#define CG6_FBC_DRAW_ILLEGAL            0x00018000
123
#define CG6_FBC_DRAW_MASK               0x00018000
124
 
125
#define CG6_FBC_BWRITE0_IGNORE          0x00000000
126
#define CG6_FBC_BWRITE0_ENABLE          0x00002000
127
#define CG6_FBC_BWRITE0_DISABLE         0x00004000
128
#define CG6_FBC_BWRITE0_ILLEGAL         0x00006000
129
#define CG6_FBC_BWRITE0_MASK            0x00006000
130
 
131
#define CG6_FBC_BWRITE1_IGNORE          0x00000000
132
#define CG6_FBC_BWRITE1_ENABLE          0x00000800
133
#define CG6_FBC_BWRITE1_DISABLE         0x00001000
134
#define CG6_FBC_BWRITE1_ILLEGAL         0x00001800
135
#define CG6_FBC_BWRITE1_MASK            0x00001800
136
 
137
#define CG6_FBC_BREAD_IGNORE            0x00000000
138
#define CG6_FBC_BREAD_0                 0x00000200
139
#define CG6_FBC_BREAD_1                 0x00000400
140
#define CG6_FBC_BREAD_ILLEGAL           0x00000600
141
#define CG6_FBC_BREAD_MASK              0x00000600
142
 
143
#define CG6_FBC_BDISP_IGNORE            0x00000000
144
#define CG6_FBC_BDISP_0                 0x00000080
145
#define CG6_FBC_BDISP_1                 0x00000100
146
#define CG6_FBC_BDISP_ILLEGAL           0x00000180
147
#define CG6_FBC_BDISP_MASK              0x00000180
148
 
149
#define CG6_FBC_INDEX_MOD               0x00000040
150
#define CG6_FBC_INDEX_MASK              0x00000030
151
 
152
/* THC definitions */
153
#define CG6_THC_MISC_REV_SHIFT          16
154
#define CG6_THC_MISC_REV_MASK           15
155
#define CG6_THC_MISC_RESET              (1 << 12)
156
#define CG6_THC_MISC_VIDEO              (1 << 10)
157
#define CG6_THC_MISC_SYNC               (1 << 9)
158
#define CG6_THC_MISC_VSYNC              (1 << 8)
159
#define CG6_THC_MISC_SYNC_ENAB          (1 << 7)
160
#define CG6_THC_MISC_CURS_RES           (1 << 6)
161
#define CG6_THC_MISC_INT_ENAB           (1 << 5)
162
#define CG6_THC_MISC_INT                (1 << 4)
163
#define CG6_THC_MISC_INIT               0x9f
164
 
165
/* The contents are unknown */
166
struct cg6_tec {
167
        int tec_matrix;
168
        int tec_clip;
169
        int tec_vdc;
170
};
171
 
172
struct cg6_thc {
173
        u32     thc_pad0[512];
174
        u32     thc_hs;         /* hsync timing */
175
        u32     thc_hsdvs;
176
        u32     thc_hd;
177
        u32     thc_vs;         /* vsync timing */
178
        u32     thc_vd;
179
        u32     thc_refresh;
180
        u32     thc_misc;
181
        u32     thc_pad1[56];
182
        u32     thc_cursxy;     /* cursor x,y position (16 bits each) */
183
        u32     thc_cursmask[32];       /* cursor mask bits */
184
        u32     thc_cursbits[32];       /* what to show where mask enabled */
185
};
186
 
187
struct cg6_fbc {
188
        u32     xxx0[1];
189
        u32     mode;
190
        u32     clip;
191
        u32     xxx1[1];
192
        u32     s;
193
        u32     draw;
194
        u32     blit;
195
        u32     font;
196
        u32     xxx2[24];
197
        u32     x0, y0, z0, color0;
198
        u32     x1, y1, z1, color1;
199
        u32     x2, y2, z2, color2;
200
        u32     x3, y3, z3, color3;
201
        u32     offx, offy;
202
        u32     xxx3[2];
203
        u32     incx, incy;
204
        u32     xxx4[2];
205
        u32     clipminx, clipminy;
206
        u32     xxx5[2];
207
        u32     clipmaxx, clipmaxy;
208
        u32     xxx6[2];
209
        u32     fg;
210
        u32     bg;
211
        u32     alu;
212
        u32     pm;
213
        u32     pixelm;
214
        u32     xxx7[2];
215
        u32     patalign;
216
        u32     pattern[8];
217
        u32     xxx8[432];
218
        u32     apointx, apointy, apointz;
219
        u32     xxx9[1];
220
        u32     rpointx, rpointy, rpointz;
221
        u32     xxx10[5];
222
        u32     pointr, pointg, pointb, pointa;
223
        u32     alinex, aliney, alinez;
224
        u32     xxx11[1];
225
        u32     rlinex, rliney, rlinez;
226
        u32     xxx12[5];
227
        u32     liner, lineg, lineb, linea;
228
        u32     atrix, atriy, atriz;
229
        u32     xxx13[1];
230
        u32     rtrix, rtriy, rtriz;
231
        u32     xxx14[5];
232
        u32     trir, trig, trib, tria;
233
        u32     aquadx, aquady, aquadz;
234
        u32     xxx15[1];
235
        u32     rquadx, rquady, rquadz;
236
        u32     xxx16[5];
237
        u32     quadr, quadg, quadb, quada;
238
        u32     arectx, arecty, arectz;
239
        u32     xxx17[1];
240
        u32     rrectx, rrecty, rrectz;
241
        u32     xxx18[5];
242
        u32     rectr, rectg, rectb, recta;
243
};
244
 
245
struct bt_regs {
246
        u32     addr;
247
        u32     color_map;
248
        u32     control;
249
        u32     cursor;
250
};
251
 
252
struct cg6_par {
253
        spinlock_t              lock;
254
        struct bt_regs          __iomem *bt;
255
        struct cg6_fbc          __iomem *fbc;
256
        struct cg6_thc          __iomem *thc;
257
        struct cg6_tec          __iomem *tec;
258
        u32                     __iomem *fhc;
259
 
260
        u32                     flags;
261
#define CG6_FLAG_BLANKED        0x00000001
262
 
263
        unsigned long           physbase;
264
        unsigned long           which_io;
265
        unsigned long           fbsize;
266
};
267
 
268
static int cg6_sync(struct fb_info *info)
269
{
270
        struct cg6_par *par = (struct cg6_par *)info->par;
271
        struct cg6_fbc __iomem *fbc = par->fbc;
272
        int limit = 10000;
273
 
274
        do {
275
                if (!(sbus_readl(&fbc->s) & 0x10000000))
276
                        break;
277
                udelay(10);
278
        } while (--limit > 0);
279
 
280
        return 0;
281
}
282
 
283
/**
284
 *      cg6_fillrect -  Draws a rectangle on the screen.
285
 *
286
 *      @info: frame buffer structure that represents a single frame buffer
287
 *      @rect: structure defining the rectagle and operation.
288
 */
289
static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
290
{
291
        struct cg6_par *par = (struct cg6_par *)info->par;
292
        struct cg6_fbc __iomem *fbc = par->fbc;
293
        unsigned long flags;
294
        s32 val;
295
 
296
        /* CG6 doesn't handle ROP_XOR */
297
 
298
        spin_lock_irqsave(&par->lock, flags);
299
 
300
        cg6_sync(info);
301
 
302
        sbus_writel(rect->color, &fbc->fg);
303
        sbus_writel(~(u32)0, &fbc->pixelm);
304
        sbus_writel(0xea80ff00, &fbc->alu);
305
        sbus_writel(0, &fbc->s);
306
        sbus_writel(0, &fbc->clip);
307
        sbus_writel(~(u32)0, &fbc->pm);
308
        sbus_writel(rect->dy, &fbc->arecty);
309
        sbus_writel(rect->dx, &fbc->arectx);
310
        sbus_writel(rect->dy + rect->height, &fbc->arecty);
311
        sbus_writel(rect->dx + rect->width, &fbc->arectx);
312
        do {
313
                val = sbus_readl(&fbc->draw);
314
        } while (val < 0 && (val & 0x20000000));
315
        spin_unlock_irqrestore(&par->lock, flags);
316
}
317
 
318
/**
319
 *      cg6_copyarea - Copies one area of the screen to another area.
320
 *
321
 *      @info: frame buffer structure that represents a single frame buffer
322
 *      @area: Structure providing the data to copy the framebuffer contents
323
 *              from one region to another.
324
 *
325
 *      This drawing operation copies a rectangular area from one area of the
326
 *      screen to another area.
327
 */
328
static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area)
329
{
330
        struct cg6_par *par = (struct cg6_par *)info->par;
331
        struct cg6_fbc __iomem *fbc = par->fbc;
332
        unsigned long flags;
333
        int i;
334
 
335
        spin_lock_irqsave(&par->lock, flags);
336
 
337
        cg6_sync(info);
338
 
339
        sbus_writel(0xff, &fbc->fg);
340
        sbus_writel(0x00, &fbc->bg);
341
        sbus_writel(~0, &fbc->pixelm);
342
        sbus_writel(0xe880cccc, &fbc->alu);
343
        sbus_writel(0, &fbc->s);
344
        sbus_writel(0, &fbc->clip);
345
 
346
        sbus_writel(area->sy, &fbc->y0);
347
        sbus_writel(area->sx, &fbc->x0);
348
        sbus_writel(area->sy + area->height - 1, &fbc->y1);
349
        sbus_writel(area->sx + area->width - 1, &fbc->x1);
350
        sbus_writel(area->dy, &fbc->y2);
351
        sbus_writel(area->dx, &fbc->x2);
352
        sbus_writel(area->dy + area->height - 1, &fbc->y3);
353
        sbus_writel(area->dx + area->width - 1, &fbc->x3);
354
        do {
355
                i = sbus_readl(&fbc->blit);
356
        } while (i < 0 && (i & 0x20000000));
357
        spin_unlock_irqrestore(&par->lock, flags);
358
}
359
 
360
/**
361
 *      cg6_imageblit - Copies a image from system memory to the screen.
362
 *
363
 *      @info: frame buffer structure that represents a single frame buffer
364
 *      @image: structure defining the image.
365
 */
366
static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
367
{
368
        struct cg6_par *par = (struct cg6_par *)info->par;
369
        struct cg6_fbc __iomem *fbc = par->fbc;
370
        const u8 *data = image->data;
371
        unsigned long flags;
372
        u32 x, y;
373
        int i, width;
374
 
375
        if (image->depth > 1) {
376
                cfb_imageblit(info, image);
377
                return;
378
        }
379
 
380
        spin_lock_irqsave(&par->lock, flags);
381
 
382
        cg6_sync(info);
383
 
384
        sbus_writel(image->fg_color, &fbc->fg);
385
        sbus_writel(image->bg_color, &fbc->bg);
386
        sbus_writel(0x140000, &fbc->mode);
387
        sbus_writel(0xe880fc30, &fbc->alu);
388
        sbus_writel(~(u32)0, &fbc->pixelm);
389
        sbus_writel(0, &fbc->s);
390
        sbus_writel(0, &fbc->clip);
391
        sbus_writel(0xff, &fbc->pm);
392
        sbus_writel(32, &fbc->incx);
393
        sbus_writel(0, &fbc->incy);
394
 
395
        x = image->dx;
396
        y = image->dy;
397
        for (i = 0; i < image->height; i++) {
398
                width = image->width;
399
 
400
                while (width >= 32) {
401
                        u32 val;
402
 
403
                        sbus_writel(y, &fbc->y0);
404
                        sbus_writel(x, &fbc->x0);
405
                        sbus_writel(x + 32 - 1, &fbc->x1);
406
 
407
                        val = ((u32)data[0] << 24) |
408
                              ((u32)data[1] << 16) |
409
                              ((u32)data[2] <<  8) |
410
                              ((u32)data[3] <<  0);
411
                        sbus_writel(val, &fbc->font);
412
 
413
                        data += 4;
414
                        x += 32;
415
                        width -= 32;
416
                }
417
                if (width) {
418
                        u32 val;
419
 
420
                        sbus_writel(y, &fbc->y0);
421
                        sbus_writel(x, &fbc->x0);
422
                        sbus_writel(x + width - 1, &fbc->x1);
423
                        if (width <= 8) {
424
                                val = (u32) data[0] << 24;
425
                                data += 1;
426
                        } else if (width <= 16) {
427
                                val = ((u32) data[0] << 24) |
428
                                      ((u32) data[1] << 16);
429
                                data += 2;
430
                        } else {
431
                                val = ((u32) data[0] << 24) |
432
                                      ((u32) data[1] << 16) |
433
                                      ((u32) data[2] <<  8);
434
                                data += 3;
435
                        }
436
                        sbus_writel(val, &fbc->font);
437
                }
438
 
439
                y += 1;
440
                x = image->dx;
441
        }
442
 
443
        spin_unlock_irqrestore(&par->lock, flags);
444
}
445
 
446
/**
447
 *      cg6_setcolreg - Sets a color register.
448
 *
449
 *      @regno: boolean, 0 copy local, 1 get_user() function
450
 *      @red: frame buffer colormap structure
451
 *      @green: The green value which can be up to 16 bits wide
452
 *      @blue:  The blue value which can be up to 16 bits wide.
453
 *      @transp: If supported the alpha value which can be up to 16 bits wide.
454
 *      @info: frame buffer info structure
455
 */
456
static int cg6_setcolreg(unsigned regno,
457
                         unsigned red, unsigned green, unsigned blue,
458
                         unsigned transp, struct fb_info *info)
459
{
460
        struct cg6_par *par = (struct cg6_par *)info->par;
461
        struct bt_regs __iomem *bt = par->bt;
462
        unsigned long flags;
463
 
464
        if (regno >= 256)
465
                return 1;
466
 
467
        red >>= 8;
468
        green >>= 8;
469
        blue >>= 8;
470
 
471
        spin_lock_irqsave(&par->lock, flags);
472
 
473
        sbus_writel((u32)regno << 24, &bt->addr);
474
        sbus_writel((u32)red << 24, &bt->color_map);
475
        sbus_writel((u32)green << 24, &bt->color_map);
476
        sbus_writel((u32)blue << 24, &bt->color_map);
477
 
478
        spin_unlock_irqrestore(&par->lock, flags);
479
 
480
        return 0;
481
}
482
 
483
/**
484
 *      cg6_blank - Blanks the display.
485
 *
486
 *      @blank_mode: the blank mode we want.
487
 *      @info: frame buffer structure that represents a single frame buffer
488
 */
489
static int cg6_blank(int blank, struct fb_info *info)
490
{
491
        struct cg6_par *par = (struct cg6_par *)info->par;
492
        struct cg6_thc __iomem *thc = par->thc;
493
        unsigned long flags;
494
        u32 val;
495
 
496
        spin_lock_irqsave(&par->lock, flags);
497
        val = sbus_readl(&thc->thc_misc);
498
 
499
        switch (blank) {
500
        case FB_BLANK_UNBLANK: /* Unblanking */
501
                val |= CG6_THC_MISC_VIDEO;
502
                par->flags &= ~CG6_FLAG_BLANKED;
503
                break;
504
 
505
        case FB_BLANK_NORMAL: /* Normal blanking */
506
        case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
507
        case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
508
        case FB_BLANK_POWERDOWN: /* Poweroff */
509
                val &= ~CG6_THC_MISC_VIDEO;
510
                par->flags |= CG6_FLAG_BLANKED;
511
                break;
512
        }
513
 
514
        sbus_writel(val, &thc->thc_misc);
515
        spin_unlock_irqrestore(&par->lock, flags);
516
 
517
        return 0;
518
}
519
 
520
static struct sbus_mmap_map cg6_mmap_map[] = {
521
        {
522
                .voff   = CG6_FBC,
523
                .poff   = CG6_FBC_OFFSET,
524
                .size   = PAGE_SIZE
525
        },
526
        {
527
                .voff   = CG6_TEC,
528
                .poff   = CG6_TEC_OFFSET,
529
                .size   = PAGE_SIZE
530
        },
531
        {
532
                .voff   = CG6_BTREGS,
533
                .poff   = CG6_BROOKTREE_OFFSET,
534
                .size   = PAGE_SIZE
535
        },
536
        {
537
                .voff   = CG6_FHC,
538
                .poff   = CG6_FHC_OFFSET,
539
                .size   = PAGE_SIZE
540
        },
541
        {
542
                .voff   = CG6_THC,
543
                .poff   = CG6_THC_OFFSET,
544
                .size   = PAGE_SIZE
545
        },
546
        {
547
                .voff   = CG6_ROM,
548
                .poff   = CG6_ROM_OFFSET,
549
                .size   = 0x10000
550
        },
551
        {
552
                .voff   = CG6_RAM,
553
                .poff   = CG6_RAM_OFFSET,
554
                .size   = SBUS_MMAP_FBSIZE(1)
555
        },
556
        {
557
                .voff   = CG6_DHC,
558
                .poff   = CG6_DHC_OFFSET,
559
                .size   = 0x40000
560
        },
561
        { .size = 0 }
562
};
563
 
564
static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
565
{
566
        struct cg6_par *par = (struct cg6_par *)info->par;
567
 
568
        return sbusfb_mmap_helper(cg6_mmap_map,
569
                                  par->physbase, par->fbsize,
570
                                  par->which_io, vma);
571
}
572
 
573
static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
574
{
575
        struct cg6_par *par = (struct cg6_par *)info->par;
576
 
577
        return sbusfb_ioctl_helper(cmd, arg, info,
578
                                   FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
579
}
580
 
581
/*
582
 *  Initialisation
583
 */
584
 
585
static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
586
{
587
        struct cg6_par *par = (struct cg6_par *)info->par;
588
        const char *cg6_cpu_name, *cg6_card_name;
589
        u32 conf;
590
 
591
        conf = sbus_readl(par->fhc);
592
        switch (conf & CG6_FHC_CPU_MASK) {
593
        case CG6_FHC_CPU_SPARC:
594
                cg6_cpu_name = "sparc";
595
                break;
596
        case CG6_FHC_CPU_68020:
597
                cg6_cpu_name = "68020";
598
                break;
599
        default:
600
                cg6_cpu_name = "i386";
601
                break;
602
        };
603
        if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
604
                if (par->fbsize <= 0x100000)
605
                        cg6_card_name = "TGX";
606
                else
607
                        cg6_card_name = "TGX+";
608
        } else {
609
                if (par->fbsize <= 0x100000)
610
                        cg6_card_name = "GX";
611
                else
612
                        cg6_card_name = "GX+";
613
        }
614
 
615
        sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
616
        info->fix.id[sizeof(info->fix.id) - 1] = 0;
617
 
618
        info->fix.type = FB_TYPE_PACKED_PIXELS;
619
        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
620
 
621
        info->fix.line_length = linebytes;
622
 
623
        info->fix.accel = FB_ACCEL_SUN_CGSIX;
624
}
625
 
626
/* Initialize Brooktree DAC */
627
static void __devinit cg6_bt_init(struct cg6_par *par)
628
{
629
        struct bt_regs __iomem *bt = par->bt;
630
 
631
        sbus_writel(0x04 << 24, &bt->addr);      /* color planes */
632
        sbus_writel(0xff << 24, &bt->control);
633
        sbus_writel(0x05 << 24, &bt->addr);
634
        sbus_writel(0x00 << 24, &bt->control);
635
        sbus_writel(0x06 << 24, &bt->addr);      /* overlay plane */
636
        sbus_writel(0x73 << 24, &bt->control);
637
        sbus_writel(0x07 << 24, &bt->addr);
638
        sbus_writel(0x00 << 24, &bt->control);
639
}
640
 
641
static void __devinit cg6_chip_init(struct fb_info *info)
642
{
643
        struct cg6_par *par = (struct cg6_par *)info->par;
644
        struct cg6_tec __iomem *tec = par->tec;
645
        struct cg6_fbc __iomem *fbc = par->fbc;
646
        u32 rev, conf, mode;
647
        int i;
648
 
649
        /* Turn off stuff in the Transform Engine. */
650
        sbus_writel(0, &tec->tec_matrix);
651
        sbus_writel(0, &tec->tec_clip);
652
        sbus_writel(0, &tec->tec_vdc);
653
 
654
        /* Take care of bugs in old revisions. */
655
        rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
656
        if (rev < 5) {
657
                conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) |
658
                        CG6_FHC_CPU_68020 | CG6_FHC_TEST |
659
                        (11 << CG6_FHC_TEST_X_SHIFT) |
660
                        (11 << CG6_FHC_TEST_Y_SHIFT);
661
                if (rev < 2)
662
                        conf |= CG6_FHC_DST_DISABLE;
663
                sbus_writel(conf, par->fhc);
664
        }
665
 
666
        /* Set things in the FBC. Bad things appear to happen if we do
667
         * back to back store/loads on the mode register, so copy it
668
         * out instead. */
669
        mode = sbus_readl(&fbc->mode);
670
        do {
671
                i = sbus_readl(&fbc->s);
672
        } while (i & 0x10000000);
673
        mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
674
                  CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
675
                  CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
676
                  CG6_FBC_BDISP_MASK);
677
        mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
678
                 CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
679
                 CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
680
                 CG6_FBC_BDISP_0);
681
        sbus_writel(mode, &fbc->mode);
682
 
683
        sbus_writel(0, &fbc->clip);
684
        sbus_writel(0, &fbc->offx);
685
        sbus_writel(0, &fbc->offy);
686
        sbus_writel(0, &fbc->clipminx);
687
        sbus_writel(0, &fbc->clipminy);
688
        sbus_writel(info->var.xres - 1, &fbc->clipmaxx);
689
        sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
690
}
691
 
692
static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
693
                           struct cg6_par *par)
694
{
695
        if (par->fbc)
696
                of_iounmap(&op->resource[0], par->fbc, 4096);
697
        if (par->tec)
698
                of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec));
699
        if (par->thc)
700
                of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc));
701
        if (par->bt)
702
                of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs));
703
        if (par->fhc)
704
                of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
705
 
706
        if (info->screen_base)
707
                of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
708
}
709
 
710
static int __devinit cg6_probe(struct of_device *op,
711
                                const struct of_device_id *match)
712
{
713
        struct device_node *dp = op->node;
714
        struct fb_info *info;
715
        struct cg6_par *par;
716
        int linebytes, err;
717
        int dblbuf;
718
 
719
        info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev);
720
 
721
        err = -ENOMEM;
722
        if (!info)
723
                goto out_err;
724
        par = info->par;
725
 
726
        spin_lock_init(&par->lock);
727
 
728
        par->physbase = op->resource[0].start;
729
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
730
 
731
        sbusfb_fill_var(&info->var, dp->node, 8);
732
        info->var.red.length = 8;
733
        info->var.green.length = 8;
734
        info->var.blue.length = 8;
735
 
736
        linebytes = of_getintprop_default(dp, "linebytes",
737
                                          info->var.xres);
738
        par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
739
 
740
        dblbuf = of_getintprop_default(dp, "dblbuf", 0);
741
        if (dblbuf)
742
                par->fbsize *= 4;
743
 
744
        par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
745
                                4096, "cgsix fbc");
746
        par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
747
                                sizeof(struct cg6_tec), "cgsix tec");
748
        par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
749
                                sizeof(struct cg6_thc), "cgsix thc");
750
        par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
751
                                sizeof(struct bt_regs), "cgsix dac");
752
        par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
753
                                sizeof(u32), "cgsix fhc");
754
 
755
        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
756
                        FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
757
                        FBINFO_READS_FAST;
758
        info->fbops = &cg6_ops;
759
 
760
        info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
761
                                        par->fbsize, "cgsix ram");
762
        if (!par->fbc || !par->tec || !par->thc ||
763
            !par->bt || !par->fhc || !info->screen_base)
764
                goto out_unmap_regs;
765
 
766
        info->var.accel_flags = FB_ACCELF_TEXT;
767
 
768
        cg6_bt_init(par);
769
        cg6_chip_init(info);
770
        cg6_blank(0, info);
771
 
772
        if (fb_alloc_cmap(&info->cmap, 256, 0))
773
                goto out_unmap_regs;
774
 
775
        fb_set_cmap(&info->cmap, info);
776
        cg6_init_fix(info, linebytes);
777
 
778
        err = register_framebuffer(info);
779
        if (err < 0)
780
                goto out_dealloc_cmap;
781
 
782
        dev_set_drvdata(&op->dev, info);
783
 
784
        printk("%s: CGsix [%s] at %lx:%lx\n",
785
               dp->full_name, info->fix.id,
786
               par->which_io, par->physbase);
787
 
788
        return 0;
789
 
790
out_dealloc_cmap:
791
        fb_dealloc_cmap(&info->cmap);
792
 
793
out_unmap_regs:
794
        cg6_unmap_regs(op, info, par);
795
 
796
out_err:
797
        return err;
798
}
799
 
800
static int __devexit cg6_remove(struct of_device *op)
801
{
802
        struct fb_info *info = dev_get_drvdata(&op->dev);
803
        struct cg6_par *par = info->par;
804
 
805
        unregister_framebuffer(info);
806
        fb_dealloc_cmap(&info->cmap);
807
 
808
        cg6_unmap_regs(op, info, par);
809
 
810
        framebuffer_release(info);
811
 
812
        dev_set_drvdata(&op->dev, NULL);
813
 
814
        return 0;
815
}
816
 
817
static struct of_device_id cg6_match[] = {
818
        {
819
                .name = "cgsix",
820
        },
821
        {
822
                .name = "cgthree+",
823
        },
824
        {},
825
};
826
MODULE_DEVICE_TABLE(of, cg6_match);
827
 
828
static struct of_platform_driver cg6_driver = {
829
        .name           = "cg6",
830
        .match_table    = cg6_match,
831
        .probe          = cg6_probe,
832
        .remove         = __devexit_p(cg6_remove),
833
};
834
 
835
static int __init cg6_init(void)
836
{
837
        if (fb_get_options("cg6fb", NULL))
838
                return -ENODEV;
839
 
840
        return of_register_driver(&cg6_driver, &of_bus_type);
841
}
842
 
843
static void __exit cg6_exit(void)
844
{
845
        of_unregister_driver(&cg6_driver);
846
}
847
 
848
module_init(cg6_init);
849
module_exit(cg6_exit);
850
 
851
MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets");
852
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
853
MODULE_VERSION("2.0");
854
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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