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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *      HP300 Topcat framebuffer support (derived from macfb of all things)
3
 *      Phil Blundell <philb@gnu.org> 1998
4
 *      DIO-II, colour map and Catseye support by
5
 *      Kars de Jong <jongk@linux-m68k.org>, May 2004.
6
 */
7
 
8
#include <linux/module.h>
9
#include <linux/kernel.h>
10
#include <linux/errno.h>
11
#include <linux/string.h>
12
#include <linux/mm.h>
13
#include <linux/slab.h>
14
#include <linux/delay.h>
15
#include <linux/init.h>
16
#include <linux/fb.h>
17
#include <linux/dio.h>
18
 
19
#include <asm/io.h>
20
#include <asm/uaccess.h>
21
 
22
static struct fb_info fb_info = {
23
        .fix = {
24
                .id             = "HP300 ",
25
                .type           = FB_TYPE_PACKED_PIXELS,
26
                .visual         = FB_VISUAL_PSEUDOCOLOR,
27
                .accel          = FB_ACCEL_NONE,
28
        }
29
};
30
 
31
static unsigned long fb_regs;
32
static unsigned char fb_bitmask;
33
 
34
#define TC_NBLANK       0x4080
35
#define TC_WEN          0x4088
36
#define TC_REN          0x408c
37
#define TC_FBEN         0x4090
38
#define TC_PRR          0x40ea
39
 
40
/* These defines match the X window system */
41
#define RR_CLEAR        0x0
42
#define RR_COPY         0x3
43
#define RR_NOOP         0x5
44
#define RR_XOR          0x6
45
#define RR_INVERT       0xa
46
#define RR_COPYINVERTED 0xc
47
#define RR_SET          0xf
48
 
49
/* blitter regs */
50
#define BUSY            0x4044
51
#define WMRR            0x40ef
52
#define SOURCE_X        0x40f2
53
#define SOURCE_Y        0x40f6
54
#define DEST_X          0x40fa
55
#define DEST_Y          0x40fe
56
#define WHEIGHT         0x4106
57
#define WWIDTH          0x4102
58
#define WMOVE           0x409c
59
 
60
static struct fb_var_screeninfo hpfb_defined = {
61
        .red            = {
62
                .length = 8,
63
        },
64
        .green          = {
65
                .length = 8,
66
        },
67
        .blue           = {
68
                .length = 8,
69
        },
70
        .activate       = FB_ACTIVATE_NOW,
71
        .height         = -1,
72
        .width          = -1,
73
        .vmode          = FB_VMODE_NONINTERLACED,
74
};
75
 
76
static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green,
77
                          unsigned blue, unsigned transp,
78
                          struct fb_info *info)
79
{
80
        /* use MSBs */
81
        unsigned char _red  =red>>8;
82
        unsigned char _green=green>>8;
83
        unsigned char _blue =blue>>8;
84
        unsigned char _regno=regno;
85
 
86
        /*
87
         *  Set a single color register. The values supplied are
88
         *  already rounded down to the hardware's capabilities
89
         *  (according to the entries in the `var' structure). Return
90
         *  != 0 for invalid regno.
91
         */
92
 
93
        if (regno >= info->cmap.len)
94
                return 1;
95
 
96
        while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
97
 
98
        out_be16(fb_regs + 0x60ba, 0xff);
99
 
100
        out_be16(fb_regs + 0x60b2, _red);
101
        out_be16(fb_regs + 0x60b4, _green);
102
        out_be16(fb_regs + 0x60b6, _blue);
103
        out_be16(fb_regs + 0x60b8, ~_regno);
104
        out_be16(fb_regs + 0x60f0, 0xff);
105
 
106
        udelay(100);
107
 
108
        while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
109
        out_be16(fb_regs + 0x60b2, 0);
110
        out_be16(fb_regs + 0x60b4, 0);
111
        out_be16(fb_regs + 0x60b6, 0);
112
        out_be16(fb_regs + 0x60b8, 0);
113
 
114
        return 0;
115
}
116
 
117
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
118
 
119
static int hpfb_blank(int blank, struct fb_info *info)
120
{
121
        out_8(fb_regs + TC_NBLANK, (blank ? 0x00 : fb_bitmask));
122
 
123
        return 0;
124
}
125
 
126
static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr)
127
{
128
        if (rr >= 0) {
129
                while (in_8(fb_regs + BUSY) & fb_bitmask)
130
                        ;
131
        }
132
        out_8(fb_regs + TC_FBEN, fb_bitmask);
133
        if (rr >= 0) {
134
                out_8(fb_regs + TC_WEN, fb_bitmask);
135
                out_8(fb_regs + WMRR, rr);
136
        }
137
        out_be16(fb_regs + SOURCE_X, x0);
138
        out_be16(fb_regs + SOURCE_Y, y0);
139
        out_be16(fb_regs + DEST_X, x1);
140
        out_be16(fb_regs + DEST_Y, y1);
141
        out_be16(fb_regs + WWIDTH, w);
142
        out_be16(fb_regs + WHEIGHT, h);
143
        out_8(fb_regs + WMOVE, fb_bitmask);
144
}
145
 
146
static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
147
{
148
        topcat_blit(area->sx, area->sy, area->dx, area->dy, area->width, area->height, RR_COPY);
149
}
150
 
151
static void hpfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
152
{
153
        u8 clr;
154
 
155
        clr = region->color & 0xff;
156
 
157
        while (in_8(fb_regs + BUSY) & fb_bitmask)
158
                ;
159
 
160
        /* Foreground */
161
        out_8(fb_regs + TC_WEN, fb_bitmask & clr);
162
        out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_SET : RR_INVERT));
163
 
164
        /* Background */
165
        out_8(fb_regs + TC_WEN, fb_bitmask & ~clr);
166
        out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_CLEAR : RR_NOOP));
167
 
168
        topcat_blit(region->dx, region->dy, region->dx, region->dy, region->width, region->height, -1);
169
}
170
 
171
static int hpfb_sync(struct fb_info *info)
172
{
173
        /*
174
         * Since we also access the framebuffer directly, we have to wait
175
         * until the block mover is finished
176
         */
177
        while (in_8(fb_regs + BUSY) & fb_bitmask)
178
                ;
179
 
180
        out_8(fb_regs + TC_WEN, fb_bitmask);
181
        out_8(fb_regs + TC_PRR, RR_COPY);
182
        out_8(fb_regs + TC_FBEN, fb_bitmask);
183
 
184
        return 0;
185
}
186
 
187
static struct fb_ops hpfb_ops = {
188
        .owner          = THIS_MODULE,
189
        .fb_setcolreg   = hpfb_setcolreg,
190
        .fb_blank       = hpfb_blank,
191
        .fb_fillrect    = hpfb_fillrect,
192
        .fb_copyarea    = hpfb_copyarea,
193
        .fb_imageblit   = cfb_imageblit,
194
        .fb_sync        = hpfb_sync,
195
};
196
 
197
/* Common to all HP framebuffers */
198
#define HPFB_FBWMSB     0x05    /* Frame buffer width           */
199
#define HPFB_FBWLSB     0x07
200
#define HPFB_FBHMSB     0x09    /* Frame buffer height          */
201
#define HPFB_FBHLSB     0x0b
202
#define HPFB_DWMSB      0x0d    /* Display width                */
203
#define HPFB_DWLSB      0x0f
204
#define HPFB_DHMSB      0x11    /* Display height               */
205
#define HPFB_DHLSB      0x13
206
#define HPFB_NUMPLANES  0x5b    /* Number of colour planes      */
207
#define HPFB_FBOMSB     0x5d    /* Frame buffer offset          */
208
#define HPFB_FBOLSB     0x5f
209
 
210
static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
211
{
212
        unsigned long fboff, fb_width, fb_height, fb_start;
213
 
214
        fb_regs = virt_base;
215
        fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);
216
 
217
        fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16);
218
 
219
        if (phys_base >= DIOII_BASE) {
220
                fb_info.fix.smem_start += phys_base;
221
        }
222
 
223
        if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) {
224
                /* This is the magic incantation the HP X server uses to make Catseye boards work. */
225
                while (in_be16(fb_regs+0x4800) & 1)
226
                        ;
227
                out_be16(fb_regs+0x4800, 0);     /* Catseye status */
228
                out_be16(fb_regs+0x4510, 0);     /* VB */
229
                out_be16(fb_regs+0x4512, 0);     /* TCNTRL */
230
                out_be16(fb_regs+0x4514, 0);     /* ACNTRL */
231
                out_be16(fb_regs+0x4516, 0);     /* PNCNTRL */
232
                out_be16(fb_regs+0x4206, 0x90); /* RUG Command/Status */
233
                out_be16(fb_regs+0x60a2, 0);     /* Overlay Mask */
234
                out_be16(fb_regs+0x60bc, 0);     /* Ram Select */
235
        }
236
 
237
        /*
238
         *      Fill in the available video resolution
239
         */
240
        fb_width = (in_8(fb_regs + HPFB_FBWMSB) << 8) | in_8(fb_regs + HPFB_FBWLSB);
241
        fb_info.fix.line_length = fb_width;
242
        fb_height = (in_8(fb_regs + HPFB_FBHMSB) << 8) | in_8(fb_regs + HPFB_FBHLSB);
243
        fb_info.fix.smem_len = fb_width * fb_height;
244
        fb_start = (unsigned long)ioremap_writethrough(fb_info.fix.smem_start,
245
                                                       fb_info.fix.smem_len);
246
        hpfb_defined.xres = (in_8(fb_regs + HPFB_DWMSB) << 8) | in_8(fb_regs + HPFB_DWLSB);
247
        hpfb_defined.yres = (in_8(fb_regs + HPFB_DHMSB) << 8) | in_8(fb_regs + HPFB_DHLSB);
248
        hpfb_defined.xres_virtual = hpfb_defined.xres;
249
        hpfb_defined.yres_virtual = hpfb_defined.yres;
250
        hpfb_defined.bits_per_pixel = in_8(fb_regs + HPFB_NUMPLANES);
251
 
252
        printk(KERN_INFO "hpfb: framebuffer at 0x%lx, mapped to 0x%lx, size %dk\n",
253
               fb_info.fix.smem_start, fb_start, fb_info.fix.smem_len/1024);
254
        printk(KERN_INFO "hpfb: mode is %dx%dx%d, linelength=%d\n",
255
               hpfb_defined.xres, hpfb_defined.yres, hpfb_defined.bits_per_pixel, fb_info.fix.line_length);
256
 
257
        /*
258
         *      Give the hardware a bit of a prod and work out how many bits per
259
         *      pixel are supported.
260
         */
261
        out_8(fb_regs + TC_WEN, 0xff);
262
        out_8(fb_regs + TC_PRR, RR_COPY);
263
        out_8(fb_regs + TC_FBEN, 0xff);
264
        out_8(fb_start, 0xff);
265
        fb_bitmask = in_8(fb_start);
266
        out_8(fb_start, 0);
267
 
268
        /*
269
         *      Enable reading/writing of all the planes.
270
         */
271
        out_8(fb_regs + TC_WEN, fb_bitmask);
272
        out_8(fb_regs + TC_PRR, RR_COPY);
273
        out_8(fb_regs + TC_REN, fb_bitmask);
274
        out_8(fb_regs + TC_FBEN, fb_bitmask);
275
 
276
        /*
277
         *      Clear the screen.
278
         */
279
        topcat_blit(0, 0, 0, 0, fb_width, fb_height, RR_CLEAR);
280
 
281
        /*
282
         *      Let there be consoles..
283
         */
284
        if (DIO_SECID(fb_regs) == DIO_ID2_TOPCAT)
285
                strcat(fb_info.fix.id, "Topcat");
286
        else
287
                strcat(fb_info.fix.id, "Catseye");
288
        fb_info.fbops = &hpfb_ops;
289
        fb_info.flags = FBINFO_DEFAULT;
290
        fb_info.var   = hpfb_defined;
291
        fb_info.screen_base = (char *)fb_start;
292
 
293
        fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
294
 
295
        if (register_framebuffer(&fb_info) < 0) {
296
                fb_dealloc_cmap(&fb_info.cmap);
297
                iounmap(fb_info.screen_base);
298
                fb_info.screen_base = NULL;
299
                return 1;
300
        }
301
 
302
        printk(KERN_INFO "fb%d: %s frame buffer device\n",
303
               fb_info.node, fb_info.fix.id);
304
 
305
        return 0;
306
}
307
 
308
/*
309
 * Check that the secondary ID indicates that we have some hope of working with this
310
 * framebuffer.  The catseye boards are pretty much like topcats and we can muddle through.
311
 */
312
 
313
#define topcat_sid_ok(x)  (((x) == DIO_ID2_LRCATSEYE) || ((x) == DIO_ID2_HRCCATSEYE)    \
314
                           || ((x) == DIO_ID2_HRMCATSEYE) || ((x) == DIO_ID2_TOPCAT))
315
 
316
/*
317
 * Initialise the framebuffer
318
 */
319
static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
320
{
321
        unsigned long paddr, vaddr;
322
 
323
        paddr = d->resource.start;
324
        if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
325
                return -EBUSY;
326
 
327
        if (d->scode >= DIOII_SCBASE) {
328
                vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
329
        } else {
330
                vaddr = paddr + DIO_VIRADDRBASE;
331
        }
332
        printk(KERN_INFO "Topcat found at DIO select code %d "
333
               "(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff);
334
        if (hpfb_init_one(paddr, vaddr)) {
335
                if (d->scode >= DIOII_SCBASE)
336
                        iounmap((void *)vaddr);
337
                return -ENOMEM;
338
        }
339
        return 0;
340
}
341
 
342
static void __devexit hpfb_remove_one(struct dio_dev *d)
343
{
344
        unregister_framebuffer(&fb_info);
345
        if (d->scode >= DIOII_SCBASE)
346
                iounmap((void *)fb_regs);
347
        release_mem_region(d->resource.start, d->resource.end - d->resource.start);
348
}
349
 
350
static struct dio_device_id hpfb_dio_tbl[] = {
351
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) },
352
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) },
353
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) },
354
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) },
355
    { 0 }
356
};
357
 
358
static struct dio_driver hpfb_driver = {
359
    .name      = "hpfb",
360
    .id_table  = hpfb_dio_tbl,
361
    .probe     = hpfb_dio_probe,
362
    .remove    = __devexit_p(hpfb_remove_one),
363
};
364
 
365
int __init hpfb_init(void)
366
{
367
        unsigned int sid;
368
        mm_segment_t fs;
369
        unsigned char i;
370
        int err;
371
 
372
        /* Topcats can be on the internal IO bus or real DIO devices.
373
         * The internal variant sits at 0x560000; it has primary
374
         * and secondary ID registers just like the DIO version.
375
         * So we merge the two detection routines.
376
         *
377
         * Perhaps this #define should be in a global header file:
378
         * I believe it's common to all internal fbs, not just topcat.
379
         */
380
#define INTFBVADDR 0xf0560000
381
#define INTFBPADDR 0x560000
382
 
383
        if (!MACH_IS_HP300)
384
                return -ENXIO;
385
 
386
        if (fb_get_options("hpfb", NULL))
387
                return -ENODEV;
388
 
389
        err = dio_register_driver(&hpfb_driver);
390
        if (err)
391
                return err;
392
 
393
        fs = get_fs();
394
        set_fs(KERNEL_DS);
395
        err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF);
396
        set_fs(fs);
397
 
398
        if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) {
399
                if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat"))
400
                        return -EBUSY;
401
                printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid);
402
                if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) {
403
                        return -ENOMEM;
404
                }
405
        }
406
        return 0;
407
}
408
 
409
void __exit hpfb_cleanup_module(void)
410
{
411
        dio_unregister_driver(&hpfb_driver);
412
}
413
 
414
module_init(hpfb_init);
415
module_exit(hpfb_cleanup_module);
416
 
417
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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