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