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