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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/drivers/video/acornfb.c
3
 *
4
 *  Copyright (C) 1998-2001 Russell King
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2 as
8
 * published by the Free Software Foundation.
9
 *
10
 * Frame buffer code for Acorn platforms
11
 *
12
 * NOTE: Most of the modes with X!=640 will disappear shortly.
13
 * NOTE: Startup setting of HS & VS polarity not supported.
14
 *       (do we need to support it if we're coming up in 640x480?)
15
 */
16
 
17
#include <linux/config.h>
18
#include <linux/module.h>
19
#include <linux/kernel.h>
20
#include <linux/sched.h>
21
#include <linux/errno.h>
22
#include <linux/string.h>
23
#include <linux/ctype.h>
24
#include <linux/mm.h>
25
#include <linux/tty.h>
26
#include <linux/slab.h>
27
#include <linux/init.h>
28
#include <linux/fb.h>
29
 
30
#include <asm/hardware.h>
31
#include <asm/io.h>
32
#include <asm/irq.h>
33
#include <asm/mach-types.h>
34
#include <asm/uaccess.h>
35
 
36
#include <video/fbcon.h>
37
#include <video/fbcon-mfb.h>
38
#include <video/fbcon-cfb2.h>
39
#include <video/fbcon-cfb4.h>
40
#include <video/fbcon-cfb8.h>
41
#include <video/fbcon-cfb16.h>
42
#include <video/fbcon-cfb32.h>
43
 
44
#include "acornfb.h"
45
 
46
/*
47
 * VIDC machines can't do 16 or 32BPP modes.
48
 */
49
#ifdef HAS_VIDC
50
#undef FBCON_HAS_CFB16
51
#undef FBCON_HAS_CFB32
52
#endif
53
 
54
/*
55
 * Default resolution.
56
 * NOTE that it has to be supported in the table towards
57
 * the end of this file.
58
 */
59
#define DEFAULT_XRES    640
60
#define DEFAULT_YRES    480
61
/*
62
 * The order here defines which BPP we
63
 * pick depending on which resolutions
64
 * we have configured.
65
 */
66
#if   defined(FBCON_HAS_CFB4)
67
# define DEFAULT_BPP    4
68
#elif defined(FBCON_HAS_CFB8)
69
# define DEFAULT_BPP    8
70
#elif defined(FBCON_HAS_CFB16)
71
# define DEFAULT_BPP    16
72
#elif defined(FBCON_HAS_CFB2)
73
# define DEFAULT_BPP    2
74
#elif defined(FBCON_HAS_MFB)
75
# define DEFAULT_BPP    1
76
#else
77
#error No suitable framebuffers configured
78
#endif
79
 
80
 
81
/*
82
 * define this to debug the video mode selection
83
 */
84
#undef DEBUG_MODE_SELECTION
85
 
86
/*
87
 * Translation from RISC OS monitor types to actual
88
 * HSYNC and VSYNC frequency ranges.  These are
89
 * probably not right, but they're the best info I
90
 * have.  Allow 1% either way on the nominal for TVs.
91
 */
92
#define NR_MONTYPES     6
93
static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {
94
        { 15469, 15781, 49, 51, 0 },     /* TV           */
95
        {     0, 99999,  0, 99, 0 },       /* Multi Freq   */
96
        { 58608, 58608, 64, 64, 0 },     /* Hi-res mono  */
97
        { 30000, 70000, 60, 60, 0 },     /* VGA          */
98
        { 30000, 70000, 56, 75, 0 },     /* SVGA         */
99
        { 30000, 70000, 60, 60, 0 }
100
};
101
 
102
static struct display global_disp;
103
static struct fb_info fb_info;
104
static struct acornfb_par current_par;
105
static struct vidc_timing current_vidc;
106
static struct fb_var_screeninfo __initdata init_var = {};
107
 
108
extern int acornfb_depth;       /* set by setup.c */
109
extern unsigned int vram_size;  /* set by setup.c */
110
 
111
#ifdef HAS_VIDC
112
 
113
#define MAX_SIZE        480*1024
114
 
115
/* CTL     VIDC Actual
116
 * 24.000  0     8.000
117
 * 25.175  0     8.392
118
 * 36.000  0    12.000
119
 * 24.000  1    12.000
120
 * 25.175  1    12.588
121
 * 24.000  2    16.000
122
 * 25.175  2    16.783
123
 * 36.000  1    18.000
124
 * 24.000  3    24.000
125
 * 36.000  2    24.000
126
 * 25.175  3    25.175
127
 * 36.000  3    36.000
128
 */
129
struct pixclock {
130
        u_long  min_clock;
131
        u_long  max_clock;
132
        u_int   vidc_ctl;
133
        u_int   vid_ctl;
134
};
135
 
136
static struct pixclock arc_clocks[] = {
137
        /* we allow +/-1% on these */
138
        { 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz },    /*  8.000MHz */
139
        {  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz },    /* 12.000MHz */
140
        {  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz },    /* 16.000MHz */
141
        {  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },    /* 24.000MHz */
142
};
143
 
144
#ifdef CONFIG_ARCH_A5K
145
static struct pixclock a5k_clocks[] = {
146
        { 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz },    /*  8.392MHz */
147
        {  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz },    /* 12.588MHz */
148
        {  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz },    /* 16.588MHz */
149
        {  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz },    /* 18.000MHz */
150
        {  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz },    /* 25.175MHz */
151
        {  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz },    /* 36.000MHz */
152
};
153
#endif
154
 
155
static struct pixclock *
156
acornfb_valid_pixrate(u_long pixclock)
157
{
158
        u_int i;
159
 
160
        for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)
161
                if (pixclock > arc_clocks[i].min_clock &&
162
                    pixclock < arc_clocks[i].max_clock)
163
                        return arc_clocks + i;
164
 
165
#ifdef CONFIG_ARCH_A5K
166
        if (machine_is_a5k()) {
167
                for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
168
                        if (pixclock > a5k_clocks[i].min_clock &&
169
                            pixclock < a5k_clocks[i].max_clock)
170
                                return a5k_clocks + i;
171
        }
172
#endif
173
 
174
        return NULL;
175
}
176
 
177
/* VIDC Rules:
178
 * hcr  : must be even (interlace, hcr/2 must be even)
179
 * hswr : must be even
180
 * hdsr : must be odd
181
 * hder : must be odd
182
 *
183
 * vcr  : must be odd
184
 * vswr : >= 1
185
 * vdsr : >= 1
186
 * vder : >= vdsr
187
 * if interlaced, then hcr/2 must be even
188
 */
189
static void
190
acornfb_set_timing(struct fb_var_screeninfo *var)
191
{
192
        struct pixclock *pclk;
193
        struct vidc_timing vidc;
194
        u_int horiz_correction;
195
        u_int sync_len, display_start, display_end, cycle;
196
        u_int is_interlaced;
197
        u_int vid_ctl, vidc_ctl;
198
        u_int bandwidth;
199
 
200
        memset(&vidc, 0, sizeof(vidc));
201
 
202
        pclk = acornfb_valid_pixrate(var->pixclock);
203
        vidc_ctl = pclk->vidc_ctl;
204
        vid_ctl  = pclk->vid_ctl;
205
 
206
        bandwidth = var->pixclock * 8 / var->bits_per_pixel;
207
        /* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
208
        if (bandwidth > 143500)
209
                vidc_ctl |= VIDC_CTRL_FIFO_3_7;
210
        else if (bandwidth > 71750)
211
                vidc_ctl |= VIDC_CTRL_FIFO_2_6;
212
        else if (bandwidth > 35875)
213
                vidc_ctl |= VIDC_CTRL_FIFO_1_5;
214
        else
215
                vidc_ctl |= VIDC_CTRL_FIFO_0_4;
216
 
217
        switch (var->bits_per_pixel) {
218
        case 1:
219
                horiz_correction = 19;
220
                vidc_ctl |= VIDC_CTRL_1BPP;
221
                break;
222
 
223
        case 2:
224
                horiz_correction = 11;
225
                vidc_ctl |= VIDC_CTRL_2BPP;
226
                break;
227
 
228
        case 4:
229
                horiz_correction = 7;
230
                vidc_ctl |= VIDC_CTRL_4BPP;
231
                break;
232
 
233
        default:
234
        case 8:
235
                horiz_correction = 5;
236
                vidc_ctl |= VIDC_CTRL_8BPP;
237
                break;
238
        }
239
 
240
        if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
241
                vidc_ctl |= VIDC_CTRL_CSYNC;
242
        else {
243
                if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
244
                        vid_ctl |= VID_CTL_HS_NHSYNC;
245
 
246
                if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
247
                        vid_ctl |= VID_CTL_VS_NVSYNC;
248
        }
249
 
250
        sync_len        = var->hsync_len;
251
        display_start   = sync_len + var->left_margin;
252
        display_end     = display_start + var->xres;
253
        cycle           = display_end + var->right_margin;
254
 
255
        /* if interlaced, then hcr/2 must be even */
256
        is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
257
 
258
        if (is_interlaced) {
259
                vidc_ctl |= VIDC_CTRL_INTERLACE;
260
                if (cycle & 2) {
261
                        cycle += 2;
262
                        var->right_margin += 2;
263
                }
264
        }
265
 
266
        vidc.h_cycle            = (cycle - 2) / 2;
267
        vidc.h_sync_width       = (sync_len - 2) / 2;
268
        vidc.h_border_start     = (display_start - 1) / 2;
269
        vidc.h_display_start    = (display_start - horiz_correction) / 2;
270
        vidc.h_display_end      = (display_end - horiz_correction) / 2;
271
        vidc.h_border_end       = (display_end - 1) / 2;
272
        vidc.h_interlace        = (vidc.h_cycle + 1) / 2;
273
 
274
        sync_len        = var->vsync_len;
275
        display_start   = sync_len + var->upper_margin;
276
        display_end     = display_start + var->yres;
277
        cycle           = display_end + var->lower_margin;
278
 
279
        if (is_interlaced)
280
                cycle = (cycle - 3) / 2;
281
        else
282
                cycle = cycle - 1;
283
 
284
        vidc.v_cycle            = cycle;
285
        vidc.v_sync_width       = sync_len - 1;
286
        vidc.v_border_start     = display_start - 1;
287
        vidc.v_display_start    = vidc.v_border_start;
288
        vidc.v_display_end      = display_end - 1;
289
        vidc.v_border_end       = vidc.v_display_end;
290
 
291
        if (machine_is_a5k())
292
                __raw_writeb(vid_ctl, IOEB_VID_CTL);
293
 
294
        if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
295
                current_vidc = vidc;
296
 
297
                vidc_writel(0xe0000000 | vidc_ctl);
298
                vidc_writel(0x80000000 | (vidc.h_cycle << 14));
299
                vidc_writel(0x84000000 | (vidc.h_sync_width << 14));
300
                vidc_writel(0x88000000 | (vidc.h_border_start << 14));
301
                vidc_writel(0x8c000000 | (vidc.h_display_start << 14));
302
                vidc_writel(0x90000000 | (vidc.h_display_end << 14));
303
                vidc_writel(0x94000000 | (vidc.h_border_end << 14));
304
                vidc_writel(0x98000000);
305
                vidc_writel(0x9c000000 | (vidc.h_interlace << 14));
306
                vidc_writel(0xa0000000 | (vidc.v_cycle << 14));
307
                vidc_writel(0xa4000000 | (vidc.v_sync_width << 14));
308
                vidc_writel(0xa8000000 | (vidc.v_border_start << 14));
309
                vidc_writel(0xac000000 | (vidc.v_display_start << 14));
310
                vidc_writel(0xb0000000 | (vidc.v_display_end << 14));
311
                vidc_writel(0xb4000000 | (vidc.v_border_end << 14));
312
                vidc_writel(0xb8000000);
313
                vidc_writel(0xbc000000);
314
        }
315
#ifdef DEBUG_MODE_SELECTION
316
        printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
317
               var->yres, var->bits_per_pixel);
318
        printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
319
        printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
320
        printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
321
        printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
322
        printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
323
        printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
324
        printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
325
        printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
326
        printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
327
        printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
328
        printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
329
        printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
330
        printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
331
        printk(KERN_DEBUG " VIDC Ctrl (E)    : 0x%08X\n", vidc_ctl);
332
        printk(KERN_DEBUG " IOEB Ctrl        : 0x%08X\n", vid_ctl);
333
#endif
334
}
335
 
336
static inline void
337
acornfb_palette_write(u_int regno, union palette pal)
338
{
339
        vidc_writel(pal.p);
340
}
341
 
342
static inline union palette
343
acornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,
344
                       u_int trans)
345
{
346
        union palette pal;
347
 
348
        pal.p = 0;
349
        pal.vidc.reg   = regno;
350
        pal.vidc.red   = red >> 12;
351
        pal.vidc.green = green >> 12;
352
        pal.vidc.blue  = blue >> 12;
353
        return pal;
354
}
355
 
356
static void
357
acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,
358
                       u_int *trans)
359
{
360
        *red   = EXTEND4(current_par.palette[regno].vidc.red);
361
        *green = EXTEND4(current_par.palette[regno].vidc.green);
362
        *blue  = EXTEND4(current_par.palette[regno].vidc.blue);
363
        *trans = current_par.palette[regno].vidc.trans ? -1 : 0;
364
}
365
#endif
366
 
367
#ifdef HAS_VIDC20
368
#include <asm/arch/acornfb.h>
369
 
370
#define MAX_SIZE        2*1024*1024
371
 
372
/* VIDC20 has a different set of rules from the VIDC:
373
 *  hcr  : must be multiple of 4
374
 *  hswr : must be even
375
 *  hdsr : must be even
376
 *  hder : must be even
377
 *  vcr  : >= 2, (interlace, must be odd)
378
 *  vswr : >= 1
379
 *  vdsr : >= 1
380
 *  vder : >= vdsr
381
 */
382
static void
383
acornfb_set_timing(struct fb_var_screeninfo *var)
384
{
385
        struct vidc_timing vidc;
386
        u_int vcr, fsize;
387
        u_int ext_ctl, dat_ctl;
388
        u_int words_per_line;
389
 
390
        memset(&vidc, 0, sizeof(vidc));
391
 
392
        vidc.h_sync_width       = var->hsync_len - 8;
393
        vidc.h_border_start     = vidc.h_sync_width + var->left_margin + 8 - 12;
394
        vidc.h_display_start    = vidc.h_border_start + 12 - 18;
395
        vidc.h_display_end      = vidc.h_display_start + var->xres;
396
        vidc.h_border_end       = vidc.h_display_end + 18 - 12;
397
        vidc.h_cycle            = vidc.h_border_end + var->right_margin + 12 - 8;
398
        vidc.h_interlace        = vidc.h_cycle / 2;
399
        vidc.v_sync_width       = var->vsync_len - 1;
400
        vidc.v_border_start     = vidc.v_sync_width + var->upper_margin;
401
        vidc.v_display_start    = vidc.v_border_start;
402
        vidc.v_display_end      = vidc.v_display_start + var->yres;
403
        vidc.v_border_end       = vidc.v_display_end;
404
        vidc.control            = acornfb_default_control();
405
 
406
        vcr = var->vsync_len + var->upper_margin + var->yres +
407
              var->lower_margin;
408
 
409
        if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
410
                vidc.v_cycle = (vcr - 3) / 2;
411
                vidc.control |= VIDC20_CTRL_INT;
412
        } else
413
                vidc.v_cycle = vcr - 2;
414
 
415
        switch (var->bits_per_pixel) {
416
        case  1: vidc.control |= VIDC20_CTRL_1BPP;      break;
417
        case  2: vidc.control |= VIDC20_CTRL_2BPP;      break;
418
        case  4: vidc.control |= VIDC20_CTRL_4BPP;      break;
419
        default:
420
        case  8: vidc.control |= VIDC20_CTRL_8BPP;      break;
421
        case 16: vidc.control |= VIDC20_CTRL_16BPP;     break;
422
        case 32: vidc.control |= VIDC20_CTRL_32BPP;     break;
423
        }
424
 
425
        acornfb_vidc20_find_rates(&vidc, var);
426
        fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1;
427
 
428
        if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
429
                current_vidc = vidc;
430
 
431
                vidc_writel(VIDC20_CTRL| vidc.control);
432
                vidc_writel(0xd0000000 | vidc.pll_ctl);
433
                vidc_writel(0x80000000 | vidc.h_cycle);
434
                vidc_writel(0x81000000 | vidc.h_sync_width);
435
                vidc_writel(0x82000000 | vidc.h_border_start);
436
                vidc_writel(0x83000000 | vidc.h_display_start);
437
                vidc_writel(0x84000000 | vidc.h_display_end);
438
                vidc_writel(0x85000000 | vidc.h_border_end);
439
                vidc_writel(0x86000000);
440
                vidc_writel(0x87000000 | vidc.h_interlace);
441
                vidc_writel(0x90000000 | vidc.v_cycle);
442
                vidc_writel(0x91000000 | vidc.v_sync_width);
443
                vidc_writel(0x92000000 | vidc.v_border_start);
444
                vidc_writel(0x93000000 | vidc.v_display_start);
445
                vidc_writel(0x94000000 | vidc.v_display_end);
446
                vidc_writel(0x95000000 | vidc.v_border_end);
447
                vidc_writel(0x96000000);
448
                vidc_writel(0x97000000);
449
        }
450
 
451
        iomd_writel(fsize, IOMD_FSIZE);
452
 
453
        ext_ctl = acornfb_default_econtrol();
454
 
455
        if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
456
                ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;
457
        else {
458
                if (var->sync & FB_SYNC_HOR_HIGH_ACT)
459
                        ext_ctl |= VIDC20_ECTL_HS_HSYNC;
460
                else
461
                        ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
462
 
463
                if (var->sync & FB_SYNC_VERT_HIGH_ACT)
464
                        ext_ctl |= VIDC20_ECTL_VS_VSYNC;
465
                else
466
                        ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
467
        }
468
 
469
        vidc_writel(VIDC20_ECTL | ext_ctl);
470
 
471
        words_per_line = var->xres * var->bits_per_pixel / 32;
472
 
473
        if (current_par.using_vram && current_par.screen_size == 2048*1024)
474
                words_per_line /= 2;
475
 
476
        /* RiscPC doesn't use the VIDC's VRAM control. */
477
        dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line;
478
 
479
        /* The data bus width is dependent on both the type
480
         * and amount of video memory.
481
         *     DRAM     32bit low
482
         * 1MB VRAM     32bit
483
         * 2MB VRAM     64bit
484
         */
485
        if (current_par.using_vram && current_par.vram_half_sam == 2048) {
486
                dat_ctl |= VIDC20_DCTL_BUS_D63_0;
487
        } else
488
                dat_ctl |= VIDC20_DCTL_BUS_D31_0;
489
 
490
        vidc_writel(VIDC20_DCTL | dat_ctl);
491
 
492
#ifdef DEBUG_MODE_SELECTION
493
        printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
494
               var->yres, var->bits_per_pixel);
495
        printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
496
        printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
497
        printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
498
        printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
499
        printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
500
        printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
501
        printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
502
        printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
503
        printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
504
        printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
505
        printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
506
        printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
507
        printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
508
        printk(KERN_DEBUG " Ext Ctrl  (C)    : 0x%08X\n", ext_ctl);
509
        printk(KERN_DEBUG " PLL Ctrl  (D)    : 0x%08X\n", vidc.pll_ctl);
510
        printk(KERN_DEBUG " Ctrl      (E)    : 0x%08X\n", vidc.control);
511
        printk(KERN_DEBUG " Data Ctrl (F)    : 0x%08X\n", dat_ctl);
512
        printk(KERN_DEBUG " Fsize            : 0x%08X\n", fsize);
513
#endif
514
}
515
 
516
static inline void
517
acornfb_palette_write(u_int regno, union palette pal)
518
{
519
        vidc_writel(0x10000000 | regno);
520
        vidc_writel(pal.p);
521
}
522
 
523
static inline union palette
524
acornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,
525
                       u_int trans)
526
{
527
        union palette pal;
528
 
529
        pal.p = 0;
530
        pal.vidc20.red   = red >> 8;
531
        pal.vidc20.green = green >> 8;
532
        pal.vidc20.blue  = blue >> 8;
533
        return pal;
534
}
535
 
536
static void
537
acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,
538
                       u_int *trans)
539
{
540
        *red   = EXTEND8(current_par.palette[regno].vidc20.red);
541
        *green = EXTEND8(current_par.palette[regno].vidc20.green);
542
        *blue  = EXTEND8(current_par.palette[regno].vidc20.blue);
543
        *trans = EXTEND4(current_par.palette[regno].vidc20.ext);
544
}
545
#endif
546
 
547
/*
548
 * Before selecting the timing parameters, adjust
549
 * the resolution to fit the rules.
550
 */
551
static int
552
acornfb_adjust_timing(struct fb_var_screeninfo *var, int con)
553
{
554
        u_int font_line_len;
555
        u_int fontht;
556
        u_int sam_size, min_size, size;
557
        u_int nr_y;
558
 
559
        /* xres must be even */
560
        var->xres = (var->xres + 1) & ~1;
561
 
562
        /*
563
         * We don't allow xres_virtual to differ from xres
564
         */
565
        var->xres_virtual = var->xres;
566
        var->xoffset = 0;
567
 
568
        /*
569
         * Find the font height
570
         */
571
        if (con == -1)
572
                fontht = fontheight(&global_disp);
573
        else
574
                fontht = fontheight(fb_display + con);
575
 
576
        if (fontht == 0)
577
                fontht = 8;
578
 
579
        if (current_par.using_vram)
580
                sam_size = current_par.vram_half_sam * 2;
581
        else
582
                sam_size = 16;
583
 
584
        /*
585
         * Now, find a value for yres_virtual which allows
586
         * us to do ywrap scrolling.  The value of
587
         * yres_virtual must be such that the end of the
588
         * displayable frame buffer must be aligned with
589
         * the start of a font line.
590
         */
591
        font_line_len = var->xres * var->bits_per_pixel * fontht / 8;
592
        min_size = var->xres * var->yres * var->bits_per_pixel / 8;
593
 
594
        /*
595
         * If minimum screen size is greater than that we have
596
         * available, reject it.
597
         */
598
        if (min_size > current_par.screen_size)
599
                return -EINVAL;
600
 
601
        /* Find int 'y', such that y * fll == s * sam < maxsize
602
         * y = s * sam / fll; s = maxsize / sam
603
         */
604
        for (size = current_par.screen_size; min_size <= size;
605
             size -= sam_size) {
606
                nr_y = size / font_line_len;
607
 
608
                if (nr_y * font_line_len == size)
609
                        break;
610
        }
611
 
612
        if (var->accel_flags & FB_ACCELF_TEXT) {
613
                if (min_size > size) {
614
                        /*
615
                         * failed, use ypan
616
                         */
617
                        size = current_par.screen_size;
618
                        var->yres_virtual = size / (font_line_len / fontht);
619
                } else
620
                        var->yres_virtual = nr_y * fontht;
621
        }
622
 
623
        current_par.screen_end = current_par.screen_base_p + size;
624
 
625
        /*
626
         * Fix yres & yoffset if needed.
627
         */
628
        if (var->yres > var->yres_virtual)
629
                var->yres = var->yres_virtual;
630
 
631
        if (var->vmode & FB_VMODE_YWRAP) {
632
                if (var->yoffset > var->yres_virtual)
633
                        var->yoffset = var->yres_virtual;
634
        } else {
635
                if (var->yoffset + var->yres > var->yres_virtual)
636
                        var->yoffset = var->yres_virtual - var->yres;
637
        }
638
 
639
        /* hsync_len must be even */
640
        var->hsync_len = (var->hsync_len + 1) & ~1;
641
 
642
#ifdef HAS_VIDC
643
        /* left_margin must be odd */
644
        if ((var->left_margin & 1) == 0) {
645
                var->left_margin -= 1;
646
                var->right_margin += 1;
647
        }
648
 
649
        /* right_margin must be odd */
650
        var->right_margin |= 1;
651
#elif defined(HAS_VIDC20)
652
        /* left_margin must be even */
653
        if (var->left_margin & 1) {
654
                var->left_margin += 1;
655
                var->right_margin -= 1;
656
        }
657
 
658
        /* right_margin must be even */
659
        if (var->right_margin & 1)
660
                var->right_margin += 1;
661
#endif
662
 
663
        if (var->vsync_len < 1)
664
                var->vsync_len = 1;
665
 
666
        return 0;
667
}
668
 
669
static int
670
acornfb_validate_timing(struct fb_var_screeninfo *var,
671
                        struct fb_monspecs *monspecs)
672
{
673
        unsigned long hs, vs;
674
 
675
        /*
676
         * hs(Hz) = 10^12 / (pixclock * xtotal)
677
         * vs(Hz) = hs(Hz) / ytotal
678
         *
679
         * No need to do long long divisions or anything
680
         * like that if you factor it correctly
681
         */
682
        hs = 1953125000 / var->pixclock;
683
        hs = hs * 512 /
684
             (var->xres + var->left_margin + var->right_margin + var->hsync_len);
685
        vs = hs /
686
             (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);
687
 
688
        return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&
689
                hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;
690
}
691
 
692
static inline void
693
acornfb_update_dma(struct fb_var_screeninfo *var)
694
{
695
        int off = (var->yoffset * var->xres_virtual *
696
                   var->bits_per_pixel) >> 3;
697
 
698
#if defined(HAS_MEMC)
699
        memc_write(VDMA_INIT, off >> 2);
700
#elif defined(HAS_IOMD)
701
        iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT);
702
#endif
703
}
704
 
705
static int
706
acornfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
707
                  u_int *trans, struct fb_info *info)
708
{
709
        if (regno >= current_par.palette_size)
710
                return 1;
711
 
712
        acornfb_palette_decode(regno, red, green, blue, trans);
713
 
714
        return 0;
715
}
716
 
717
/*
718
 * We have to take note of the VIDC20's 16-bit palette here.
719
 * The VIDC20 looks up a 16 bit pixel as follows:
720
 *
721
 *   bits   111111
722
 *          5432109876543210
723
 *   red            ++++++++  (8 bits,  7 to 0)
724
 *  green       ++++++++      (8 bits, 11 to 4)
725
 *   blue   ++++++++          (8 bits, 15 to 8)
726
 *
727
 * We use a pixel which looks like:
728
 *
729
 *   bits   111111
730
 *          5432109876543210
731
 *   red               +++++  (5 bits,  4 to  0)
732
 *  green         +++++       (5 bits,  9 to  5)
733
 *   blue    +++++            (5 bits, 14 to 10)
734
 */
735
static int
736
acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
737
                  u_int trans, struct fb_info *info)
738
{
739
        union palette pal;
740
        int bpp = fb_display[current_par.currcon].var.bits_per_pixel;
741
 
742
        if (regno >= current_par.palette_size)
743
                return 1;
744
 
745
        pal = acornfb_palette_encode(regno, red, green, blue, trans);
746
        current_par.palette[regno] = pal;
747
 
748
#ifdef FBCON_HAS_CFB32
749
        if (bpp == 32 && regno < 16) {
750
                current_par.cmap.cfb32[regno] =
751
                                regno | regno << 8 | regno << 16;
752
        }
753
#endif
754
#ifdef FBCON_HAS_CFB16
755
        if (bpp == 16 && regno < 16) {
756
                int i;
757
 
758
                current_par.cmap.cfb16[regno] =
759
                                regno | regno << 5 | regno << 10;
760
 
761
                pal.p = 0;
762
                vidc_writel(0x10000000);
763
                for (i = 0; i < 256; i += 1) {
764
                        pal.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;
765
                        pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
766
                        pal.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
767
                        vidc_writel(pal.p);
768
                        /* Palette register pointer auto-increments */
769
                }
770
        } else
771
#endif
772
                acornfb_palette_write(regno, pal);
773
 
774
        return 0;
775
}
776
 
777
static int
778
acornfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
779
                 struct fb_info *info)
780
{
781
        int err = 0;
782
 
783
        if (con == current_par.currcon)
784
                err = fb_get_cmap(cmap, kspc, acornfb_getcolreg, info);
785
        else if (fb_display[con].cmap.len)
786
                fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
787
        else
788
                fb_copy_cmap(fb_default_cmap(current_par.palette_size),
789
                             cmap, kspc ? 0 : 2);
790
        return err;
791
}
792
 
793
static int
794
acornfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
795
                 struct fb_info *info)
796
{
797
        int err = 0;
798
 
799
        if (!fb_display[con].cmap.len)
800
                err = fb_alloc_cmap(&fb_display[con].cmap,
801
                                    current_par.palette_size, 0);
802
        if (!err) {
803
                if (con == current_par.currcon)
804
                        err = fb_set_cmap(cmap, kspc, acornfb_setcolreg,
805
                                          info);
806
                else
807
                        fb_copy_cmap(cmap, &fb_display[con].cmap,
808
                                     kspc ? 0 : 1);
809
        }
810
        return err;
811
}
812
 
813
static int
814
acornfb_decode_var(struct fb_var_screeninfo *var, int con)
815
{
816
        int err;
817
 
818
#if defined(HAS_VIDC20)
819
        var->red.offset    = 0;
820
        var->red.length    = 8;
821
        var->green         = var->red;
822
        var->blue          = var->red;
823
        var->transp.offset = 0;
824
        var->transp.length = 4;
825
#elif defined(HAS_VIDC)
826
        var->red.length    = 4;
827
        var->green         = var->red;
828
        var->blue          = var->red;
829
        var->transp.length = 1;
830
#endif
831
 
832
        switch (var->bits_per_pixel) {
833
#ifdef FBCON_HAS_MFB
834
        case 1:
835
                break;
836
#endif
837
#ifdef FBCON_HAS_CFB2
838
        case 2:
839
                break;
840
#endif
841
#ifdef FBCON_HAS_CFB4
842
        case 4:
843
                break;
844
#endif
845
#ifdef FBCON_HAS_CFB8
846
        case 8:
847
                break;
848
#endif
849
#ifdef FBCON_HAS_CFB16
850
        case 16:
851
                var->red.offset    = 0;
852
                var->red.length    = 5;
853
                var->green.offset  = 5;
854
                var->green.length  = 5;
855
                var->blue.offset   = 10;
856
                var->blue.length   = 5;
857
                var->transp.offset = 15;
858
                var->transp.length = 1;
859
                break;
860
#endif
861
#ifdef FBCON_HAS_CFB32
862
        case 32:
863
                var->red.offset    = 0;
864
                var->red.length    = 8;
865
                var->green.offset  = 8;
866
                var->green.length  = 8;
867
                var->blue.offset   = 16;
868
                var->blue.length   = 8;
869
                var->transp.offset = 24;
870
                var->transp.length = 4;
871
                break;
872
#endif
873
        default:
874
                return -EINVAL;
875
        }
876
 
877
        /*
878
         * Check to see if the pixel rate is valid.
879
         */
880
        if (!var->pixclock || !acornfb_valid_pixrate(var->pixclock))
881
                return -EINVAL;
882
 
883
        /*
884
         * Validate and adjust the resolution to
885
         * match the video generator hardware.
886
         */
887
        err = acornfb_adjust_timing(var, con);
888
        if (err)
889
                return err;
890
 
891
        /*
892
         * Validate the timing against the
893
         * monitor hardware.
894
         */
895
        return acornfb_validate_timing(var, &fb_info.monspecs);
896
}
897
 
898
static int
899
acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
900
{
901
        struct display *display;
902
 
903
        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
904
        strcpy(fix->id, "Acorn");
905
 
906
        if (con >= 0)
907
                display = fb_display + con;
908
        else
909
                display = &global_disp;
910
 
911
        fix->smem_start  = current_par.screen_base_p;
912
        fix->smem_len    = current_par.screen_size;
913
        fix->type        = display->type;
914
        fix->type_aux    = display->type_aux;
915
        fix->xpanstep    = 0;
916
        fix->ypanstep    = display->ypanstep;
917
        fix->ywrapstep   = display->ywrapstep;
918
        fix->visual      = display->visual;
919
        fix->line_length = display->line_length;
920
        fix->accel       = FB_ACCEL_NONE;
921
 
922
        return 0;
923
}
924
 
925
static int
926
acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
927
{
928
        if (con == -1) {
929
                *var = global_disp.var;
930
        } else
931
                *var = fb_display[con].var;
932
 
933
        return 0;
934
}
935
 
936
static int
937
acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
938
{
939
        struct display *display;
940
        int err, chgvar = 0;
941
 
942
        if (con >= 0)
943
                display = fb_display + con;
944
        else
945
                display = &global_disp;
946
 
947
        err = acornfb_decode_var(var, con);
948
        if (err)
949
                return err;
950
 
951
        switch (var->activate & FB_ACTIVATE_MASK) {
952
        case FB_ACTIVATE_TEST:
953
                return 0;
954
 
955
        case FB_ACTIVATE_NXTOPEN:
956
        case FB_ACTIVATE_NOW:
957
                break;
958
 
959
        default:
960
                return -EINVAL;
961
        }
962
 
963
        if (con >= 0) {
964
                if (display->var.xres != var->xres)
965
                        chgvar = 1;
966
                if (display->var.yres != var->yres)
967
                        chgvar = 1;
968
                if (display->var.xres_virtual != var->xres_virtual)
969
                        chgvar = 1;
970
                if (display->var.yres_virtual != var->yres_virtual)
971
                        chgvar = 1;
972
                if (memcmp(&display->var.red, &var->red, sizeof(var->red)))
973
                        chgvar = 1;
974
                if (memcmp(&display->var.green, &var->green, sizeof(var->green)))
975
                        chgvar = 1;
976
                if (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))
977
                        chgvar = 1;
978
        }
979
 
980
        display->var = *var;
981
        display->var.activate &= ~FB_ACTIVATE_ALL;
982
 
983
        if (var->activate & FB_ACTIVATE_ALL)
984
                global_disp.var = display->var;
985
 
986
        switch (display->var.bits_per_pixel) {
987
#ifdef FBCON_HAS_MFB
988
        case 1:
989
                current_par.palette_size = 2;
990
                display->dispsw = &fbcon_mfb;
991
                display->visual = FB_VISUAL_MONO10;
992
                break;
993
#endif
994
#ifdef FBCON_HAS_CFB2
995
        case 2:
996
                current_par.palette_size = 4;
997
                display->dispsw = &fbcon_cfb2;
998
                display->visual = FB_VISUAL_PSEUDOCOLOR;
999
                break;
1000
#endif
1001
#ifdef FBCON_HAS_CFB4
1002
        case 4:
1003
                current_par.palette_size = 16;
1004
                display->dispsw = &fbcon_cfb4;
1005
                display->visual = FB_VISUAL_PSEUDOCOLOR;
1006
                break;
1007
#endif
1008
#ifdef FBCON_HAS_CFB8
1009
        case 8:
1010
                current_par.palette_size = VIDC_PALETTE_SIZE;
1011
                display->dispsw = &fbcon_cfb8;
1012
#ifdef HAS_VIDC
1013
                display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
1014
#else
1015
                display->visual = FB_VISUAL_PSEUDOCOLOR;
1016
#endif
1017
                break;
1018
#endif
1019
#ifdef FBCON_HAS_CFB16
1020
        case 16:
1021
                current_par.palette_size = 32;
1022
                display->dispsw = &fbcon_cfb16;
1023
                display->dispsw_data = current_par.cmap.cfb16;
1024
                display->visual = FB_VISUAL_DIRECTCOLOR;
1025
                break;
1026
#endif
1027
#ifdef FBCON_HAS_CFB32
1028
        case 32:
1029
                current_par.palette_size = VIDC_PALETTE_SIZE;
1030
                display->dispsw = &fbcon_cfb32;
1031
                display->dispsw_data = current_par.cmap.cfb32;
1032
                display->visual = FB_VISUAL_TRUECOLOR;
1033
                break;
1034
#endif
1035
        default:
1036
                display->dispsw = &fbcon_dummy;
1037
                break;
1038
        }
1039
 
1040
        display->screen_base    = (char *)current_par.screen_base;
1041
        display->type           = FB_TYPE_PACKED_PIXELS;
1042
        display->type_aux       = 0;
1043
        display->ypanstep       = 1;
1044
        display->ywrapstep      = 1;
1045
        display->line_length    =
1046
        display->next_line      = (var->xres * var->bits_per_pixel) / 8;
1047
        display->can_soft_blank = display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
1048
        display->inverse        = 0;
1049
 
1050
        if (chgvar && info && info->changevar)
1051
                info->changevar(con);
1052
 
1053
        if (con == current_par.currcon) {
1054
                struct fb_cmap *cmap;
1055
                unsigned long start, size;
1056
                int control;
1057
 
1058
#if defined(HAS_MEMC)
1059
                start   = 0;
1060
                size    = current_par.screen_size - VDMA_XFERSIZE;
1061
                control = 0;
1062
 
1063
                memc_write(VDMA_START, start);
1064
                memc_write(VDMA_END, size >> 2);
1065
#elif defined(HAS_IOMD)
1066
 
1067
                start = current_par.screen_base_p;
1068
                size  = current_par.screen_end;
1069
 
1070
                if (current_par.using_vram) {
1071
                        size -= current_par.vram_half_sam;
1072
                        control = DMA_CR_E | (current_par.vram_half_sam / 256);
1073
                } else {
1074
                        size -= 16;
1075
                        control = DMA_CR_E | DMA_CR_D | 16;
1076
                }
1077
 
1078
                iomd_writel(start,   IOMD_VIDSTART);
1079
                iomd_writel(size,    IOMD_VIDEND);
1080
                iomd_writel(control, IOMD_VIDCR);
1081
#endif
1082
                acornfb_update_dma(var);
1083
                acornfb_set_timing(var);
1084
 
1085
                if (display->cmap.len)
1086
                        cmap = &display->cmap;
1087
                else
1088
                        cmap = fb_default_cmap(current_par.palette_size);
1089
 
1090
                fb_set_cmap(cmap, 1, acornfb_setcolreg, info);
1091
        }
1092
        return 0;
1093
}
1094
 
1095
static int
1096
acornfb_pan_display(struct fb_var_screeninfo *var, int con,
1097
                    struct fb_info *info)
1098
{
1099
        u_int y_bottom;
1100
 
1101
        if (var->xoffset)
1102
                return -EINVAL;
1103
 
1104
        y_bottom = var->yoffset;
1105
 
1106
        if (!(var->vmode & FB_VMODE_YWRAP))
1107
                y_bottom += var->yres;
1108
 
1109
        if (y_bottom > fb_display[con].var.yres_virtual)
1110
                return -EINVAL;
1111
 
1112
        acornfb_update_dma(var);
1113
 
1114
        fb_display[con].var.yoffset = var->yoffset;
1115
        if (var->vmode & FB_VMODE_YWRAP)
1116
                fb_display[con].var.vmode |= FB_VMODE_YWRAP;
1117
        else
1118
                fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
1119
 
1120
        return 0;
1121
}
1122
 
1123
/*
1124
 * Note that we are entered with the kernel locked.
1125
 */
1126
static int
1127
acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
1128
{
1129
        unsigned long off, start;
1130
        u32 len;
1131
 
1132
        off = vma->vm_pgoff << PAGE_SHIFT;
1133
 
1134
        start = current_par.screen_base_p;
1135
        len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size;
1136
        start &= PAGE_MASK;
1137
        if ((vma->vm_end - vma->vm_start + off) > len)
1138
                return -EINVAL;
1139
        off += start;
1140
        vma->vm_pgoff = off >> PAGE_SHIFT;
1141
 
1142
#ifdef CONFIG_CPU_32
1143
        pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE;
1144
#endif
1145
 
1146
        /*
1147
         * Don't alter the page protection flags; we want to keep the area
1148
         * cached for better performance.  This does mean that we may miss
1149
         * some updates to the screen occasionally, but process switches
1150
         * should cause the caches and buffers to be flushed often enough.
1151
         */
1152
        if (io_remap_page_range(vma->vm_start, off,
1153
                                vma->vm_end - vma->vm_start,
1154
                                vma->vm_page_prot))
1155
                return -EAGAIN;
1156
        return 0;
1157
}
1158
 
1159
static struct fb_ops acornfb_ops = {
1160
        owner:          THIS_MODULE,
1161
        fb_get_fix:     acornfb_get_fix,
1162
        fb_get_var:     acornfb_get_var,
1163
        fb_set_var:     acornfb_set_var,
1164
        fb_get_cmap:    acornfb_get_cmap,
1165
        fb_set_cmap:    acornfb_set_cmap,
1166
        fb_pan_display: acornfb_pan_display,
1167
        fb_mmap:        acornfb_mmap,
1168
};
1169
 
1170
static int
1171
acornfb_updatevar(int con, struct fb_info *info)
1172
{
1173
        if (con == current_par.currcon)
1174
                acornfb_update_dma(&fb_display[con].var);
1175
 
1176
        return 0;
1177
}
1178
 
1179
static int
1180
acornfb_switch(int con, struct fb_info *info)
1181
{
1182
        struct fb_cmap *cmap;
1183
 
1184
        if (current_par.currcon >= 0) {
1185
                cmap = &fb_display[current_par.currcon].cmap;
1186
 
1187
                if (cmap->len)
1188
                        fb_get_cmap(cmap, 1, acornfb_getcolreg, info);
1189
        }
1190
 
1191
        current_par.currcon = con;
1192
 
1193
        fb_display[con].var.activate = FB_ACTIVATE_NOW;
1194
 
1195
        acornfb_set_var(&fb_display[con].var, con, info);
1196
 
1197
        return 0;
1198
}
1199
 
1200
static void
1201
acornfb_blank(int blank, struct fb_info *info)
1202
{
1203
        union palette p;
1204
        int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel;
1205
 
1206
#ifdef FBCON_HAS_CFB16
1207
        if (bpp == 16) {
1208
                p.p = 0;
1209
 
1210
                for (i = 0; i < 256; i++) {
1211
                        if (blank)
1212
                                p = acornfb_palette_encode(i, 0, 0, 0, 0);
1213
                        else {
1214
                                p.vidc20.red   = current_par.palette[ i       & 31].vidc20.red;
1215
                                p.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
1216
                                p.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
1217
                        }
1218
                        acornfb_palette_write(i, current_par.palette[i]);
1219
                }
1220
        } else
1221
#endif
1222
        {
1223
                for (i = 0; i < current_par.palette_size; i++) {
1224
                        if (blank)
1225
                                p = acornfb_palette_encode(i, 0, 0, 0, 0);
1226
                        else
1227
                                p = current_par.palette[i];
1228
 
1229
                        acornfb_palette_write(i, p);
1230
                }
1231
        }
1232
}
1233
 
1234
/*
1235
 * Everything after here is initialisation!!!
1236
 */
1237
static struct fb_videomode modedb[] __initdata = {
1238
        {       /* 320x256 @ 50Hz */
1239
                NULL, 50,  320,  256, 125000,  92,  62,  35, 19,  38, 2,
1240
                FB_SYNC_COMP_HIGH_ACT,
1241
                FB_VMODE_NONINTERLACED
1242
        }, {    /* 640x250 @ 50Hz, 15.6 kHz hsync */
1243
                NULL, 50,  640,  250,  62500, 185, 123,  38, 21,  76, 3,
1244
                0,
1245
                FB_VMODE_NONINTERLACED
1246
        }, {    /* 640x256 @ 50Hz, 15.6 kHz hsync */
1247
                NULL, 50,  640,  256,  62500, 185, 123,  35, 18,  76, 3,
1248
                0,
1249
                FB_VMODE_NONINTERLACED
1250
        }, {    /* 640x512 @ 50Hz, 26.8 kHz hsync */
1251
                NULL, 50,  640,  512,  41667, 113,  87,  18,  1,  56, 3,
1252
                0,
1253
                FB_VMODE_NONINTERLACED
1254
        }, {    /* 640x250 @ 70Hz, 31.5 kHz hsync */
1255
                NULL, 70,  640,  250,  39722,  48,  16, 109, 88,  96, 2,
1256
                0,
1257
                FB_VMODE_NONINTERLACED
1258
        }, {    /* 640x256 @ 70Hz, 31.5 kHz hsync */
1259
                NULL, 70,  640,  256,  39722,  48,  16, 106, 85,  96, 2,
1260
                0,
1261
                FB_VMODE_NONINTERLACED
1262
        }, {    /* 640x352 @ 70Hz, 31.5 kHz hsync */
1263
                NULL, 70,  640,  352,  39722,  48,  16,  58, 37,  96, 2,
1264
                0,
1265
                FB_VMODE_NONINTERLACED
1266
        }, {    /* 640x480 @ 60Hz, 31.5 kHz hsync */
1267
                NULL, 60,  640,  480,  39722,  48,  16,  32, 11,  96, 2,
1268
                0,
1269
                FB_VMODE_NONINTERLACED
1270
        }, {    /* 800x600 @ 56Hz, 35.2 kHz hsync */
1271
                NULL, 56,  800,  600,  27778, 101,  23,  22,  1, 100, 2,
1272
                0,
1273
                FB_VMODE_NONINTERLACED
1274
        }, {    /* 896x352 @ 60Hz, 21.8 kHz hsync */
1275
                NULL, 60,  896,  352,  41667,  59,  27,   9,  0, 118, 3,
1276
                0,
1277
                FB_VMODE_NONINTERLACED
1278
        }, {    /* 1024x 768 @ 60Hz, 48.4 kHz hsync */
1279
                NULL, 60, 1024,  768,  15385, 160,  24,  29,  3, 136, 6,
1280
                0,
1281
                FB_VMODE_NONINTERLACED
1282
        }, {    /* 1280x1024 @ 60Hz, 63.8 kHz hsync */
1283
                NULL, 60, 1280, 1024,   9090, 186,  96,  38,  1, 160, 3,
1284
                0,
1285
                FB_VMODE_NONINTERLACED
1286
        }
1287
};
1288
 
1289
static struct fb_videomode __initdata
1290
acornfb_default_mode = {
1291
        name:           NULL,
1292
        refresh:        60,
1293
        xres:           640,
1294
        yres:           480,
1295
        pixclock:       39722,
1296
        left_margin:    56,
1297
        right_margin:   16,
1298
        upper_margin:   34,
1299
        lower_margin:   9,
1300
        hsync_len:      88,
1301
        vsync_len:      2,
1302
        sync:           0,
1303
        vmode:          FB_VMODE_NONINTERLACED
1304
};
1305
 
1306
static void __init
1307
acornfb_init_fbinfo(void)
1308
{
1309
        static int first = 1;
1310
 
1311
        if (!first)
1312
                return;
1313
        first = 0;
1314
 
1315
        strcpy(fb_info.modename, "Acorn");
1316
        strcpy(fb_info.fontname, "Acorn8x8");
1317
 
1318
        fb_info.node               = -1;
1319
        fb_info.fbops              = &acornfb_ops;
1320
        fb_info.disp               = &global_disp;
1321
        fb_info.changevar          = NULL;
1322
        fb_info.switch_con         = acornfb_switch;
1323
        fb_info.updatevar          = acornfb_updatevar;
1324
        fb_info.blank              = acornfb_blank;
1325
        fb_info.flags              = FBINFO_FLAG_DEFAULT;
1326
 
1327
        global_disp.dispsw         = &fbcon_dummy;
1328
 
1329
        /*
1330
         * setup initial parameters
1331
         */
1332
        memset(&init_var, 0, sizeof(init_var));
1333
 
1334
#if defined(HAS_VIDC20)
1335
        init_var.red.length        = 8;
1336
        init_var.transp.length     = 4;
1337
#elif defined(HAS_VIDC)
1338
        init_var.red.length        = 4;
1339
        init_var.transp.length     = 1;
1340
#endif
1341
        init_var.green             = init_var.red;
1342
        init_var.blue              = init_var.red;
1343
        init_var.nonstd            = 0;
1344
        init_var.activate          = FB_ACTIVATE_NOW;
1345
        init_var.height            = -1;
1346
        init_var.width             = -1;
1347
        init_var.vmode             = FB_VMODE_NONINTERLACED;
1348
        init_var.accel_flags       = FB_ACCELF_TEXT;
1349
 
1350
        current_par.dram_size      = 0;
1351
        current_par.montype        = -1;
1352
        current_par.dpms           = 0;
1353
}
1354
 
1355
/*
1356
 * setup acornfb options:
1357
 *
1358
 *  font:fontname
1359
 *      Set fontname
1360
 *
1361
 *  mon:hmin-hmax:vmin-vmax:dpms:width:height
1362
 *      Set monitor parameters:
1363
 *              hmin   = horizontal minimum frequency (Hz)
1364
 *              hmax   = horizontal maximum frequency (Hz)      (optional)
1365
 *              vmin   = vertical minimum frequency (Hz)
1366
 *              vmax   = vertical maximum frequency (Hz)        (optional)
1367
 *              dpms   = DPMS supported?                        (optional)
1368
 *              width  = width of picture in mm.                (optional)
1369
 *              height = height of picture in mm.               (optional)
1370
 *
1371
 * montype:type
1372
 *      Set RISC-OS style monitor type:
1373
 *              0 (or tv)       - TV frequency
1374
 *              1 (or multi)    - Multi frequency
1375
 *              2 (or hires)    - Hi-res monochrome
1376
 *              3 (or vga)      - VGA
1377
 *              4 (or svga)     - SVGA
1378
 *              auto, or option missing
1379
 *                              - try hardware detect
1380
 *
1381
 * dram:size
1382
 *      Set the amount of DRAM to use for the frame buffer
1383
 *      (even if you have VRAM).
1384
 *      size can optionally be followed by 'M' or 'K' for
1385
 *      MB or KB respectively.
1386
 */
1387
static void __init
1388
acornfb_parse_font(char *opt)
1389
{
1390
        strcpy(fb_info.fontname, opt);
1391
}
1392
 
1393
static void __init
1394
acornfb_parse_mon(char *opt)
1395
{
1396
        char *p = opt;
1397
 
1398
        current_par.montype = -2;
1399
 
1400
        fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0);
1401
        if (*p == '-')
1402
                fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0);
1403
        else
1404
                fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
1405
 
1406
        if (*p != ':')
1407
                goto bad;
1408
 
1409
        fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0);
1410
        if (*p == '-')
1411
                fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0);
1412
        else
1413
                fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
1414
 
1415
        if (*p != ':')
1416
                goto check_values;
1417
 
1418
        fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0);
1419
 
1420
        if (*p != ':')
1421
                goto check_values;
1422
 
1423
        init_var.width = simple_strtoul(p + 1, &p, 0);
1424
 
1425
        if (*p != ':')
1426
                goto check_values;
1427
 
1428
        init_var.height = simple_strtoul(p + 1, NULL, 0);
1429
 
1430
check_values:
1431
        if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin ||
1432
            fb_info.monspecs.vfmax < fb_info.monspecs.vfmin)
1433
                goto bad;
1434
        return;
1435
 
1436
bad:
1437
        printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt);
1438
        current_par.montype = -1;
1439
}
1440
 
1441
static void __init
1442
acornfb_parse_montype(char *opt)
1443
{
1444
        current_par.montype = -2;
1445
 
1446
        if (strncmp(opt, "tv", 2) == 0) {
1447
                opt += 2;
1448
                current_par.montype = 0;
1449
        } else if (strncmp(opt, "multi", 5) == 0) {
1450
                opt += 5;
1451
                current_par.montype = 1;
1452
        } else if (strncmp(opt, "hires", 5) == 0) {
1453
                opt += 5;
1454
                current_par.montype = 2;
1455
        } else if (strncmp(opt, "vga", 3) == 0) {
1456
                opt += 3;
1457
                current_par.montype = 3;
1458
        } else if (strncmp(opt, "svga", 4) == 0) {
1459
                opt += 4;
1460
                current_par.montype = 4;
1461
        } else if (strncmp(opt, "auto", 4) == 0) {
1462
                opt += 4;
1463
                current_par.montype = -1;
1464
        } else if (isdigit(*opt))
1465
                current_par.montype = simple_strtoul(opt, &opt, 0);
1466
 
1467
        if (current_par.montype == -2 ||
1468
            current_par.montype > NR_MONTYPES) {
1469
                printk(KERN_ERR "acornfb: unknown monitor type: %s\n",
1470
                        opt);
1471
                current_par.montype = -1;
1472
        } else
1473
        if (opt && *opt) {
1474
                if (strcmp(opt, ",dpms") == 0)
1475
                        current_par.dpms = 1;
1476
                else
1477
                        printk(KERN_ERR
1478
                               "acornfb: unknown monitor option: %s\n",
1479
                               opt);
1480
        }
1481
}
1482
 
1483
static void __init
1484
acornfb_parse_dram(char *opt)
1485
{
1486
        unsigned int size;
1487
 
1488
        size = simple_strtoul(opt, &opt, 0);
1489
 
1490
        if (opt) {
1491
                switch (*opt) {
1492
                case 'M':
1493
                case 'm':
1494
                        size *= 1024;
1495
                case 'K':
1496
                case 'k':
1497
                        size *= 1024;
1498
                default:
1499
                        break;
1500
                }
1501
        }
1502
 
1503
        current_par.dram_size = size;
1504
}
1505
 
1506
static struct options {
1507
        char *name;
1508
        void (*parse)(char *opt);
1509
} opt_table[] __initdata = {
1510
        { "font",    acornfb_parse_font    },
1511
        { "mon",     acornfb_parse_mon     },
1512
        { "montype", acornfb_parse_montype },
1513
        { "dram",    acornfb_parse_dram    },
1514
        { NULL, NULL }
1515
};
1516
 
1517
int __init
1518
acornfb_setup(char *options)
1519
{
1520
        struct options *optp;
1521
        char *opt;
1522
 
1523
        if (!options || !*options)
1524
                return 0;
1525
 
1526
        acornfb_init_fbinfo();
1527
 
1528
        while ((opt = strsep(&options, ",")) != NULL) {
1529
                if (!*opt)
1530
                        continue;
1531
 
1532
                for (optp = opt_table; optp->name; optp++) {
1533
                        int optlen;
1534
 
1535
                        optlen = strlen(optp->name);
1536
 
1537
                        if (strncmp(opt, optp->name, optlen) == 0 &&
1538
                            opt[optlen] == ':') {
1539
                                optp->parse(opt + optlen + 1);
1540
                                break;
1541
                        }
1542
                }
1543
 
1544
                if (!optp->name)
1545
                        printk(KERN_ERR "acornfb: unknown parameter: %s\n",
1546
                               opt);
1547
        }
1548
        return 0;
1549
}
1550
 
1551
/*
1552
 * Detect type of monitor connected
1553
 *  For now, we just assume SVGA
1554
 */
1555
static int __init
1556
acornfb_detect_monitortype(void)
1557
{
1558
        return 4;
1559
}
1560
 
1561
/*
1562
 * This enables the unused memory to be freed on older Acorn machines.
1563
 */
1564
static inline void
1565
free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
1566
{
1567
        int mb_freed = 0;
1568
 
1569
        /*
1570
         * Align addresses
1571
         */
1572
        virtual_start = PAGE_ALIGN(virtual_start);
1573
        virtual_end = PAGE_ALIGN(virtual_end);
1574
 
1575
        while (virtual_start < virtual_end) {
1576
                struct page *page;
1577
 
1578
                /*
1579
                 * Clear page reserved bit,
1580
                 * set count to 1, and free
1581
                 * the page.
1582
                 */
1583
                page = virt_to_page(virtual_start);
1584
                ClearPageReserved(page);
1585
                atomic_set(&page->count, 1);
1586
                free_page(virtual_start);
1587
 
1588
                virtual_start += PAGE_SIZE;
1589
                mb_freed += PAGE_SIZE / 1024;
1590
        }
1591
 
1592
        printk("acornfb: freed %dK memory\n", mb_freed);
1593
}
1594
 
1595
int __init
1596
acornfb_init(void)
1597
{
1598
        unsigned long size;
1599
        u_int h_sync, v_sync;
1600
        int rc, i;
1601
 
1602
        acornfb_init_fbinfo();
1603
 
1604
        if (current_par.montype == -1)
1605
                current_par.montype = acornfb_detect_monitortype();
1606
 
1607
        if (current_par.montype == -1 || current_par.montype > NR_MONTYPES)
1608
                current_par.montype = 4;
1609
 
1610
        if (current_par.montype >= 0) {
1611
                fb_info.monspecs = monspecs[current_par.montype];
1612
                fb_info.monspecs.dpms = current_par.dpms;
1613
        }
1614
 
1615
        /*
1616
         * Try to select a suitable default mode
1617
         */
1618
        for (i = 0; i < sizeof(modedb) / sizeof(*modedb); i++) {
1619
                unsigned long hs;
1620
 
1621
                hs = modedb[i].refresh *
1622
                     (modedb[i].yres + modedb[i].upper_margin +
1623
                      modedb[i].lower_margin + modedb[i].vsync_len);
1624
                if (modedb[i].xres == DEFAULT_XRES &&
1625
                    modedb[i].yres == DEFAULT_YRES &&
1626
                    modedb[i].refresh >= fb_info.monspecs.vfmin &&
1627
                    modedb[i].refresh <= fb_info.monspecs.vfmax &&
1628
                    hs                >= fb_info.monspecs.hfmin &&
1629
                    hs                <= fb_info.monspecs.hfmax) {
1630
                        acornfb_default_mode = modedb[i];
1631
                        break;
1632
                }
1633
        }
1634
 
1635
        current_par.currcon        = -1;
1636
        current_par.screen_base    = SCREEN_BASE;
1637
        current_par.screen_base_p  = SCREEN_START;
1638
        current_par.using_vram     = 0;
1639
 
1640
        /*
1641
         * If vram_size is set, we are using VRAM in
1642
         * a Risc PC.  However, if the user has specified
1643
         * an amount of DRAM then use that instead.
1644
         */
1645
        if (vram_size && !current_par.dram_size) {
1646
                size = vram_size;
1647
                current_par.vram_half_sam = vram_size / 1024;
1648
                current_par.using_vram = 1;
1649
        } else if (current_par.dram_size)
1650
                size = current_par.dram_size;
1651
        else
1652
                size = MAX_SIZE;
1653
 
1654
        /*
1655
         * Limit maximum screen size.
1656
         */
1657
        if (size > MAX_SIZE)
1658
                size = MAX_SIZE;
1659
 
1660
        size = PAGE_ALIGN(size);
1661
 
1662
#if defined(HAS_VIDC20)
1663
        if (!current_par.using_vram) {
1664
                /*
1665
                 * RiscPC needs to allocate the DRAM memory
1666
                 * for the framebuffer if we are not using
1667
                 * VRAM.  Archimedes/A5000 machines use a
1668
                 * fixed address for their framebuffers.
1669
                 */
1670
                int order = 0;
1671
                unsigned long page, top;
1672
                while (size > (PAGE_SIZE * (1 << order)))
1673
                        order++;
1674
                current_par.screen_base = __get_free_pages(GFP_KERNEL, order);
1675
                if (current_par.screen_base == 0) {
1676
                        printk(KERN_ERR "acornfb: unable to allocate screen "
1677
                               "memory\n");
1678
                        return -ENOMEM;
1679
                }
1680
                top = current_par.screen_base + (PAGE_SIZE * (1 << order));
1681
                /* Mark the framebuffer pages as reserved so mmap will work. */
1682
                for (page = current_par.screen_base;
1683
                     page < PAGE_ALIGN(current_par.screen_base + size);
1684
                     page += PAGE_SIZE)
1685
                        SetPageReserved(virt_to_page(page));
1686
                /* Hand back any excess pages that we allocated. */
1687
                for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE)
1688
                        free_page(page);
1689
                current_par.screen_base_p =
1690
                        virt_to_phys((void *)current_par.screen_base);
1691
        }
1692
#endif
1693
#if defined(HAS_VIDC)
1694
        /*
1695
         * Free unused pages
1696
         */
1697
        free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
1698
#endif
1699
 
1700
        current_par.screen_size    = size;
1701
        current_par.palette_size   = VIDC_PALETTE_SIZE;
1702
 
1703
        /*
1704
         * Lookup the timing for this resolution.  If we can't
1705
         * find it, then we can't restore it if we change
1706
         * the resolution, so we disable this feature.
1707
         */
1708
        do {
1709
                rc = fb_find_mode(&init_var, &fb_info, NULL, modedb,
1710
                                 sizeof(modedb) / sizeof(*modedb),
1711
                                 &acornfb_default_mode, DEFAULT_BPP);
1712
                /*
1713
                 * If we found an exact match, all ok.
1714
                 */
1715
                if (rc == 1)
1716
                        break;
1717
 
1718
                rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0,
1719
                                  &acornfb_default_mode, DEFAULT_BPP);
1720
                /*
1721
                 * If we found an exact match, all ok.
1722
                 */
1723
                if (rc == 1)
1724
                        break;
1725
 
1726
                rc = fb_find_mode(&init_var, &fb_info, NULL, modedb,
1727
                                 sizeof(modedb) / sizeof(*modedb),
1728
                                 &acornfb_default_mode, DEFAULT_BPP);
1729
                if (rc)
1730
                        break;
1731
 
1732
                rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0,
1733
                                  &acornfb_default_mode, DEFAULT_BPP);
1734
        } while (0);
1735
 
1736
        /*
1737
         * If we didn't find an exact match, try the
1738
         * generic database.
1739
         */
1740
        if (rc == 0) {
1741
                printk("Acornfb: no valid mode found\n");
1742
                return -EINVAL;
1743
        }
1744
 
1745
        h_sync = 1953125000 / init_var.pixclock;
1746
        h_sync = h_sync * 512 / (init_var.xres + init_var.left_margin +
1747
                 init_var.right_margin + init_var.hsync_len);
1748
        v_sync = h_sync / (init_var.yres + init_var.upper_margin +
1749
                 init_var.lower_margin + init_var.vsync_len);
1750
 
1751
        printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, "
1752
                "%d.%03dkHz, %dHz\n",
1753
                current_par.screen_size / 1024,
1754
                current_par.using_vram ? 'V' : 'D',
1755
                VIDC_NAME, init_var.xres, init_var.yres,
1756
                h_sync / 1000, h_sync % 1000, v_sync);
1757
 
1758
        printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n",
1759
                fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000,
1760
                fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000,
1761
                fb_info.monspecs.vfmin, fb_info.monspecs.vfmax,
1762
                fb_info.monspecs.dpms ? ", DPMS" : "");
1763
 
1764
        if (acornfb_set_var(&init_var, -1, &fb_info))
1765
                printk(KERN_ERR "Acornfb: unable to set display parameters\n");
1766
 
1767
        if (register_framebuffer(&fb_info) < 0)
1768
                return -EINVAL;
1769
        return 0;
1770
}
1771
 
1772
MODULE_AUTHOR("Russell King");
1773
MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");
1774
MODULE_LICENSE("GPL");
1775
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

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