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