This source file includes following definitions.
- acornfb_set_timing
- acornfb_setcolreg
- acornfb_adjust_timing
- acornfb_validate_timing
- acornfb_update_dma
- acornfb_check_var
- acornfb_set_par
- acornfb_pan_display
- acornfb_init_fbinfo
- acornfb_parse_mon
- acornfb_parse_montype
- acornfb_parse_dram
- acornfb_setup
- acornfb_detect_monitortype
- free_unused_pages
- acornfb_probe
- acornfb_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
21 #include <linux/ctype.h>
22 #include <linux/mm.h>
23 #include <linux/init.h>
24 #include <linux/fb.h>
25 #include <linux/platform_device.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/io.h>
28 #include <linux/gfp.h>
29
30 #include <mach/hardware.h>
31 #include <asm/irq.h>
32 #include <asm/mach-types.h>
33 #include <asm/pgtable.h>
34
35 #include "acornfb.h"
36
37
38
39
40
41
42 #define DEFAULT_XRES 640
43 #define DEFAULT_YRES 480
44 #define DEFAULT_BPP 4
45
46
47
48
49 #undef DEBUG_MODE_SELECTION
50
51
52
53
54
55
56
57 #define NR_MONTYPES 6
58 static struct fb_monspecs monspecs[NR_MONTYPES] = {
59 {
60 .hfmin = 15469,
61 .hfmax = 15781,
62 .vfmin = 49,
63 .vfmax = 51,
64 }, {
65 .hfmin = 0,
66 .hfmax = 99999,
67 .vfmin = 0,
68 .vfmax = 199,
69 }, {
70 .hfmin = 58608,
71 .hfmax = 58608,
72 .vfmin = 64,
73 .vfmax = 64,
74 }, {
75 .hfmin = 30000,
76 .hfmax = 70000,
77 .vfmin = 60,
78 .vfmax = 60,
79 }, {
80 .hfmin = 30000,
81 .hfmax = 70000,
82 .vfmin = 56,
83 .vfmax = 75,
84 }, {
85 .hfmin = 30000,
86 .hfmax = 70000,
87 .vfmin = 60,
88 .vfmax = 60,
89 }
90 };
91
92 static struct fb_info fb_info;
93 static struct acornfb_par current_par;
94 static struct vidc_timing current_vidc;
95
96 extern unsigned int vram_size;
97
98 #ifdef HAS_VIDC20
99 #include <mach/acornfb.h>
100
101 #define MAX_SIZE (2*1024*1024)
102
103
104
105
106
107
108
109
110
111
112
113 static void acornfb_set_timing(struct fb_info *info)
114 {
115 struct fb_var_screeninfo *var = &info->var;
116 struct vidc_timing vidc;
117 u_int vcr, fsize;
118 u_int ext_ctl, dat_ctl;
119 u_int words_per_line;
120
121 memset(&vidc, 0, sizeof(vidc));
122
123 vidc.h_sync_width = var->hsync_len - 8;
124 vidc.h_border_start = vidc.h_sync_width + var->left_margin + 8 - 12;
125 vidc.h_display_start = vidc.h_border_start + 12 - 18;
126 vidc.h_display_end = vidc.h_display_start + var->xres;
127 vidc.h_border_end = vidc.h_display_end + 18 - 12;
128 vidc.h_cycle = vidc.h_border_end + var->right_margin + 12 - 8;
129 vidc.h_interlace = vidc.h_cycle / 2;
130 vidc.v_sync_width = var->vsync_len - 1;
131 vidc.v_border_start = vidc.v_sync_width + var->upper_margin;
132 vidc.v_display_start = vidc.v_border_start;
133 vidc.v_display_end = vidc.v_display_start + var->yres;
134 vidc.v_border_end = vidc.v_display_end;
135 vidc.control = acornfb_default_control();
136
137 vcr = var->vsync_len + var->upper_margin + var->yres +
138 var->lower_margin;
139
140 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
141 vidc.v_cycle = (vcr - 3) / 2;
142 vidc.control |= VIDC20_CTRL_INT;
143 } else
144 vidc.v_cycle = vcr - 2;
145
146 switch (var->bits_per_pixel) {
147 case 1: vidc.control |= VIDC20_CTRL_1BPP; break;
148 case 2: vidc.control |= VIDC20_CTRL_2BPP; break;
149 case 4: vidc.control |= VIDC20_CTRL_4BPP; break;
150 default:
151 case 8: vidc.control |= VIDC20_CTRL_8BPP; break;
152 case 16: vidc.control |= VIDC20_CTRL_16BPP; break;
153 case 32: vidc.control |= VIDC20_CTRL_32BPP; break;
154 }
155
156 acornfb_vidc20_find_rates(&vidc, var);
157 fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1;
158
159 if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) {
160 current_vidc = vidc;
161
162 vidc_writel(VIDC20_CTRL | vidc.control);
163 vidc_writel(0xd0000000 | vidc.pll_ctl);
164 vidc_writel(0x80000000 | vidc.h_cycle);
165 vidc_writel(0x81000000 | vidc.h_sync_width);
166 vidc_writel(0x82000000 | vidc.h_border_start);
167 vidc_writel(0x83000000 | vidc.h_display_start);
168 vidc_writel(0x84000000 | vidc.h_display_end);
169 vidc_writel(0x85000000 | vidc.h_border_end);
170 vidc_writel(0x86000000);
171 vidc_writel(0x87000000 | vidc.h_interlace);
172 vidc_writel(0x90000000 | vidc.v_cycle);
173 vidc_writel(0x91000000 | vidc.v_sync_width);
174 vidc_writel(0x92000000 | vidc.v_border_start);
175 vidc_writel(0x93000000 | vidc.v_display_start);
176 vidc_writel(0x94000000 | vidc.v_display_end);
177 vidc_writel(0x95000000 | vidc.v_border_end);
178 vidc_writel(0x96000000);
179 vidc_writel(0x97000000);
180 }
181
182 iomd_writel(fsize, IOMD_FSIZE);
183
184 ext_ctl = acornfb_default_econtrol();
185
186 if (var->sync & FB_SYNC_COMP_HIGH_ACT)
187 ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;
188 else {
189 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
190 ext_ctl |= VIDC20_ECTL_HS_HSYNC;
191 else
192 ext_ctl |= VIDC20_ECTL_HS_NHSYNC;
193
194 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
195 ext_ctl |= VIDC20_ECTL_VS_VSYNC;
196 else
197 ext_ctl |= VIDC20_ECTL_VS_NVSYNC;
198 }
199
200 vidc_writel(VIDC20_ECTL | ext_ctl);
201
202 words_per_line = var->xres * var->bits_per_pixel / 32;
203
204 if (current_par.using_vram && info->fix.smem_len == 2048*1024)
205 words_per_line /= 2;
206
207
208 dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line;
209
210
211
212
213
214
215
216 if (current_par.using_vram && current_par.vram_half_sam == 2048)
217 dat_ctl |= VIDC20_DCTL_BUS_D63_0;
218 else
219 dat_ctl |= VIDC20_DCTL_BUS_D31_0;
220
221 vidc_writel(VIDC20_DCTL | dat_ctl);
222
223 #ifdef DEBUG_MODE_SELECTION
224 printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
225 var->yres, var->bits_per_pixel);
226 printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle);
227 printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width);
228 printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start);
229 printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start);
230 printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end);
231 printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end);
232 printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace);
233 printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle);
234 printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width);
235 printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start);
236 printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start);
237 printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end);
238 printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end);
239 printk(KERN_DEBUG " Ext Ctrl (C) : 0x%08X\n", ext_ctl);
240 printk(KERN_DEBUG " PLL Ctrl (D) : 0x%08X\n", vidc.pll_ctl);
241 printk(KERN_DEBUG " Ctrl (E) : 0x%08X\n", vidc.control);
242 printk(KERN_DEBUG " Data Ctrl (F) : 0x%08X\n", dat_ctl);
243 printk(KERN_DEBUG " Fsize : 0x%08X\n", fsize);
244 #endif
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 static int
266 acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
267 u_int trans, struct fb_info *info)
268 {
269 union palette pal;
270
271 if (regno >= current_par.palette_size)
272 return 1;
273
274 if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
275 u32 pseudo_val;
276
277 pseudo_val = regno << info->var.red.offset;
278 pseudo_val |= regno << info->var.green.offset;
279 pseudo_val |= regno << info->var.blue.offset;
280
281 ((u32 *)info->pseudo_palette)[regno] = pseudo_val;
282 }
283
284 pal.p = 0;
285 pal.vidc20.red = red >> 8;
286 pal.vidc20.green = green >> 8;
287 pal.vidc20.blue = blue >> 8;
288
289 current_par.palette[regno] = pal;
290
291 if (info->var.bits_per_pixel == 16) {
292 int i;
293
294 pal.p = 0;
295 vidc_writel(0x10000000);
296 for (i = 0; i < 256; i += 1) {
297 pal.vidc20.red = current_par.palette[i & 31].vidc20.red;
298 pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
299 pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue;
300 vidc_writel(pal.p);
301
302 }
303 } else {
304 vidc_writel(0x10000000 | regno);
305 vidc_writel(pal.p);
306 }
307
308 return 0;
309 }
310 #endif
311
312
313
314
315
316 static int
317 acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht)
318 {
319 u_int font_line_len, sam_size, min_size, size, nr_y;
320
321
322 var->xres = (var->xres + 1) & ~1;
323
324
325
326
327 var->xres_virtual = var->xres;
328 var->xoffset = 0;
329
330 if (current_par.using_vram)
331 sam_size = current_par.vram_half_sam * 2;
332 else
333 sam_size = 16;
334
335
336
337
338
339
340
341
342 font_line_len = var->xres * var->bits_per_pixel * fontht / 8;
343 min_size = var->xres * var->yres * var->bits_per_pixel / 8;
344
345
346
347
348
349 if (min_size > info->fix.smem_len)
350 return -EINVAL;
351
352
353
354
355 for (size = info->fix.smem_len;
356 nr_y = size / font_line_len, min_size <= size;
357 size -= sam_size) {
358 if (nr_y * font_line_len == size)
359 break;
360 }
361 nr_y *= fontht;
362
363 if (var->accel_flags & FB_ACCELF_TEXT) {
364 if (min_size > size) {
365
366
367
368 size = info->fix.smem_len;
369 var->yres_virtual = size / (font_line_len / fontht);
370 } else
371 var->yres_virtual = nr_y;
372 } else if (var->yres_virtual > nr_y)
373 var->yres_virtual = nr_y;
374
375 current_par.screen_end = info->fix.smem_start + size;
376
377
378
379
380 if (var->yres > var->yres_virtual)
381 var->yres = var->yres_virtual;
382
383 if (var->vmode & FB_VMODE_YWRAP) {
384 if (var->yoffset > var->yres_virtual)
385 var->yoffset = var->yres_virtual;
386 } else {
387 if (var->yoffset + var->yres > var->yres_virtual)
388 var->yoffset = var->yres_virtual - var->yres;
389 }
390
391
392 var->hsync_len = (var->hsync_len + 1) & ~1;
393
394 #if defined(HAS_VIDC20)
395
396 if (var->left_margin & 1) {
397 var->left_margin += 1;
398 var->right_margin -= 1;
399 }
400
401
402 if (var->right_margin & 1)
403 var->right_margin += 1;
404 #endif
405
406 if (var->vsync_len < 1)
407 var->vsync_len = 1;
408
409 return 0;
410 }
411
412 static int
413 acornfb_validate_timing(struct fb_var_screeninfo *var,
414 struct fb_monspecs *monspecs)
415 {
416 unsigned long hs, vs;
417
418
419
420
421
422
423
424
425 hs = 1953125000 / var->pixclock;
426 hs = hs * 512 /
427 (var->xres + var->left_margin + var->right_margin + var->hsync_len);
428 vs = hs /
429 (var->yres + var->upper_margin + var->lower_margin + var->vsync_len);
430
431 return (vs >= monspecs->vfmin && vs <= monspecs->vfmax &&
432 hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL;
433 }
434
435 static inline void
436 acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var)
437 {
438 u_int off = var->yoffset * info->fix.line_length;
439
440 #if defined(HAS_MEMC)
441 memc_write(VDMA_INIT, off >> 2);
442 #elif defined(HAS_IOMD)
443 iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT);
444 #endif
445 }
446
447 static int
448 acornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
449 {
450 u_int fontht;
451 int err;
452
453
454
455
456 fontht = 8;
457
458 var->red.msb_right = 0;
459 var->green.msb_right = 0;
460 var->blue.msb_right = 0;
461 var->transp.msb_right = 0;
462
463 switch (var->bits_per_pixel) {
464 case 1: case 2: case 4: case 8:
465 var->red.offset = 0;
466 var->red.length = var->bits_per_pixel;
467 var->green = var->red;
468 var->blue = var->red;
469 var->transp.offset = 0;
470 var->transp.length = 0;
471 break;
472
473 #ifdef HAS_VIDC20
474 case 16:
475 var->red.offset = 0;
476 var->red.length = 5;
477 var->green.offset = 5;
478 var->green.length = 5;
479 var->blue.offset = 10;
480 var->blue.length = 5;
481 var->transp.offset = 15;
482 var->transp.length = 1;
483 break;
484
485 case 32:
486 var->red.offset = 0;
487 var->red.length = 8;
488 var->green.offset = 8;
489 var->green.length = 8;
490 var->blue.offset = 16;
491 var->blue.length = 8;
492 var->transp.offset = 24;
493 var->transp.length = 4;
494 break;
495 #endif
496 default:
497 return -EINVAL;
498 }
499
500
501
502
503 if (!acornfb_valid_pixrate(var))
504 return -EINVAL;
505
506
507
508
509
510 err = acornfb_adjust_timing(info, var, fontht);
511 if (err)
512 return err;
513
514
515
516
517
518 return acornfb_validate_timing(var, &info->monspecs);
519 }
520
521 static int acornfb_set_par(struct fb_info *info)
522 {
523 switch (info->var.bits_per_pixel) {
524 case 1:
525 current_par.palette_size = 2;
526 info->fix.visual = FB_VISUAL_MONO10;
527 break;
528 case 2:
529 current_par.palette_size = 4;
530 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
531 break;
532 case 4:
533 current_par.palette_size = 16;
534 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
535 break;
536 case 8:
537 current_par.palette_size = VIDC_PALETTE_SIZE;
538 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
539 break;
540 #ifdef HAS_VIDC20
541 case 16:
542 current_par.palette_size = 32;
543 info->fix.visual = FB_VISUAL_DIRECTCOLOR;
544 break;
545 case 32:
546 current_par.palette_size = VIDC_PALETTE_SIZE;
547 info->fix.visual = FB_VISUAL_DIRECTCOLOR;
548 break;
549 #endif
550 default:
551 BUG();
552 }
553
554 info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8;
555
556 #if defined(HAS_MEMC)
557 {
558 unsigned long size = info->fix.smem_len - VDMA_XFERSIZE;
559
560 memc_write(VDMA_START, 0);
561 memc_write(VDMA_END, size >> 2);
562 }
563 #elif defined(HAS_IOMD)
564 {
565 unsigned long start, size;
566 u_int control;
567
568 start = info->fix.smem_start;
569 size = current_par.screen_end;
570
571 if (current_par.using_vram) {
572 size -= current_par.vram_half_sam;
573 control = DMA_CR_E | (current_par.vram_half_sam / 256);
574 } else {
575 size -= 16;
576 control = DMA_CR_E | DMA_CR_D | 16;
577 }
578
579 iomd_writel(start, IOMD_VIDSTART);
580 iomd_writel(size, IOMD_VIDEND);
581 iomd_writel(control, IOMD_VIDCR);
582 }
583 #endif
584
585 acornfb_update_dma(info, &info->var);
586 acornfb_set_timing(info);
587
588 return 0;
589 }
590
591 static int
592 acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
593 {
594 u_int y_bottom = var->yoffset;
595
596 if (!(var->vmode & FB_VMODE_YWRAP))
597 y_bottom += info->var.yres;
598
599 if (y_bottom > info->var.yres_virtual)
600 return -EINVAL;
601
602 acornfb_update_dma(info, var);
603
604 return 0;
605 }
606
607 static struct fb_ops acornfb_ops = {
608 .owner = THIS_MODULE,
609 .fb_check_var = acornfb_check_var,
610 .fb_set_par = acornfb_set_par,
611 .fb_setcolreg = acornfb_setcolreg,
612 .fb_pan_display = acornfb_pan_display,
613 .fb_fillrect = cfb_fillrect,
614 .fb_copyarea = cfb_copyarea,
615 .fb_imageblit = cfb_imageblit,
616 };
617
618
619
620
621 static struct fb_videomode modedb[] = {
622 {
623 NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2,
624 FB_SYNC_COMP_HIGH_ACT,
625 FB_VMODE_NONINTERLACED
626 }, {
627 NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3,
628 0,
629 FB_VMODE_NONINTERLACED
630 }, {
631 NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3,
632 0,
633 FB_VMODE_NONINTERLACED
634 }, {
635 NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3,
636 0,
637 FB_VMODE_NONINTERLACED
638 }, {
639 NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2,
640 0,
641 FB_VMODE_NONINTERLACED
642 }, {
643 NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2,
644 0,
645 FB_VMODE_NONINTERLACED
646 }, {
647 NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2,
648 0,
649 FB_VMODE_NONINTERLACED
650 }, {
651 NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2,
652 0,
653 FB_VMODE_NONINTERLACED
654 }, {
655 NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2,
656 0,
657 FB_VMODE_NONINTERLACED
658 }, {
659 NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3,
660 0,
661 FB_VMODE_NONINTERLACED
662 }, {
663 NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
664 0,
665 FB_VMODE_NONINTERLACED
666 }, {
667 NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3,
668 0,
669 FB_VMODE_NONINTERLACED
670 }
671 };
672
673 static struct fb_videomode acornfb_default_mode = {
674 .name = NULL,
675 .refresh = 60,
676 .xres = 640,
677 .yres = 480,
678 .pixclock = 39722,
679 .left_margin = 56,
680 .right_margin = 16,
681 .upper_margin = 34,
682 .lower_margin = 9,
683 .hsync_len = 88,
684 .vsync_len = 2,
685 .sync = 0,
686 .vmode = FB_VMODE_NONINTERLACED
687 };
688
689 static void acornfb_init_fbinfo(void)
690 {
691 static int first = 1;
692
693 if (!first)
694 return;
695 first = 0;
696
697 fb_info.fbops = &acornfb_ops;
698 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
699 fb_info.pseudo_palette = current_par.pseudo_palette;
700
701 strcpy(fb_info.fix.id, "Acorn");
702 fb_info.fix.type = FB_TYPE_PACKED_PIXELS;
703 fb_info.fix.type_aux = 0;
704 fb_info.fix.xpanstep = 0;
705 fb_info.fix.ypanstep = 1;
706 fb_info.fix.ywrapstep = 1;
707 fb_info.fix.line_length = 0;
708 fb_info.fix.accel = FB_ACCEL_NONE;
709
710
711
712
713 memset(&fb_info.var, 0, sizeof(fb_info.var));
714
715 #if defined(HAS_VIDC20)
716 fb_info.var.red.length = 8;
717 fb_info.var.transp.length = 4;
718 #endif
719 fb_info.var.green = fb_info.var.red;
720 fb_info.var.blue = fb_info.var.red;
721 fb_info.var.nonstd = 0;
722 fb_info.var.activate = FB_ACTIVATE_NOW;
723 fb_info.var.height = -1;
724 fb_info.var.width = -1;
725 fb_info.var.vmode = FB_VMODE_NONINTERLACED;
726 fb_info.var.accel_flags = FB_ACCELF_TEXT;
727
728 current_par.dram_size = 0;
729 current_par.montype = -1;
730 current_par.dpms = 0;
731 }
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762 static void acornfb_parse_mon(char *opt)
763 {
764 char *p = opt;
765
766 current_par.montype = -2;
767
768 fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0);
769 if (*p == '-')
770 fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0);
771 else
772 fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
773
774 if (*p != ':')
775 goto bad;
776
777 fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0);
778 if (*p == '-')
779 fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0);
780 else
781 fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
782
783 if (*p != ':')
784 goto check_values;
785
786 fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0);
787
788 if (*p != ':')
789 goto check_values;
790
791 fb_info.var.width = simple_strtoul(p + 1, &p, 0);
792
793 if (*p != ':')
794 goto check_values;
795
796 fb_info.var.height = simple_strtoul(p + 1, NULL, 0);
797
798 check_values:
799 if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin ||
800 fb_info.monspecs.vfmax < fb_info.monspecs.vfmin)
801 goto bad;
802 return;
803
804 bad:
805 printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt);
806 current_par.montype = -1;
807 }
808
809 static void acornfb_parse_montype(char *opt)
810 {
811 current_par.montype = -2;
812
813 if (strncmp(opt, "tv", 2) == 0) {
814 opt += 2;
815 current_par.montype = 0;
816 } else if (strncmp(opt, "multi", 5) == 0) {
817 opt += 5;
818 current_par.montype = 1;
819 } else if (strncmp(opt, "hires", 5) == 0) {
820 opt += 5;
821 current_par.montype = 2;
822 } else if (strncmp(opt, "vga", 3) == 0) {
823 opt += 3;
824 current_par.montype = 3;
825 } else if (strncmp(opt, "svga", 4) == 0) {
826 opt += 4;
827 current_par.montype = 4;
828 } else if (strncmp(opt, "auto", 4) == 0) {
829 opt += 4;
830 current_par.montype = -1;
831 } else if (isdigit(*opt))
832 current_par.montype = simple_strtoul(opt, &opt, 0);
833
834 if (current_par.montype == -2 ||
835 current_par.montype > NR_MONTYPES) {
836 printk(KERN_ERR "acornfb: unknown monitor type: %s\n",
837 opt);
838 current_par.montype = -1;
839 } else
840 if (opt && *opt) {
841 if (strcmp(opt, ",dpms") == 0)
842 current_par.dpms = 1;
843 else
844 printk(KERN_ERR
845 "acornfb: unknown monitor option: %s\n",
846 opt);
847 }
848 }
849
850 static void acornfb_parse_dram(char *opt)
851 {
852 unsigned int size;
853
854 size = simple_strtoul(opt, &opt, 0);
855
856 if (opt) {
857 switch (*opt) {
858 case 'M':
859 case 'm':
860 size *= 1024;
861
862 case 'K':
863 case 'k':
864 size *= 1024;
865 default:
866 break;
867 }
868 }
869
870 current_par.dram_size = size;
871 }
872
873 static struct options {
874 char *name;
875 void (*parse)(char *opt);
876 } opt_table[] = {
877 { "mon", acornfb_parse_mon },
878 { "montype", acornfb_parse_montype },
879 { "dram", acornfb_parse_dram },
880 { NULL, NULL }
881 };
882
883 static int acornfb_setup(char *options)
884 {
885 struct options *optp;
886 char *opt;
887
888 if (!options || !*options)
889 return 0;
890
891 acornfb_init_fbinfo();
892
893 while ((opt = strsep(&options, ",")) != NULL) {
894 if (!*opt)
895 continue;
896
897 for (optp = opt_table; optp->name; optp++) {
898 int optlen;
899
900 optlen = strlen(optp->name);
901
902 if (strncmp(opt, optp->name, optlen) == 0 &&
903 opt[optlen] == ':') {
904 optp->parse(opt + optlen + 1);
905 break;
906 }
907 }
908
909 if (!optp->name)
910 printk(KERN_ERR "acornfb: unknown parameter: %s\n",
911 opt);
912 }
913 return 0;
914 }
915
916
917
918
919
920 static int acornfb_detect_monitortype(void)
921 {
922 return 4;
923 }
924
925
926
927
928
929
930 static inline void
931 free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
932 {
933 int mb_freed = 0;
934
935
936
937
938 virtual_start = PAGE_ALIGN(virtual_start);
939 virtual_end = PAGE_ALIGN(virtual_end);
940
941 while (virtual_start < virtual_end) {
942 struct page *page;
943
944
945
946
947
948
949 page = virt_to_page(virtual_start);
950 __free_reserved_page(page);
951
952 virtual_start += PAGE_SIZE;
953 mb_freed += PAGE_SIZE / 1024;
954 }
955
956 printk("acornfb: freed %dK memory\n", mb_freed);
957 }
958
959 static int acornfb_probe(struct platform_device *dev)
960 {
961 unsigned long size;
962 u_int h_sync, v_sync;
963 int rc, i;
964 char *option = NULL;
965
966 if (fb_get_options("acornfb", &option))
967 return -ENODEV;
968 acornfb_setup(option);
969
970 acornfb_init_fbinfo();
971
972 current_par.dev = &dev->dev;
973
974 if (current_par.montype == -1)
975 current_par.montype = acornfb_detect_monitortype();
976
977 if (current_par.montype == -1 || current_par.montype > NR_MONTYPES)
978 current_par.montype = 4;
979
980 if (current_par.montype >= 0) {
981 fb_info.monspecs = monspecs[current_par.montype];
982 fb_info.monspecs.dpms = current_par.dpms;
983 }
984
985
986
987
988 for (i = 0; i < ARRAY_SIZE(modedb); i++) {
989 unsigned long hs;
990
991 hs = modedb[i].refresh *
992 (modedb[i].yres + modedb[i].upper_margin +
993 modedb[i].lower_margin + modedb[i].vsync_len);
994 if (modedb[i].xres == DEFAULT_XRES &&
995 modedb[i].yres == DEFAULT_YRES &&
996 modedb[i].refresh >= fb_info.monspecs.vfmin &&
997 modedb[i].refresh <= fb_info.monspecs.vfmax &&
998 hs >= fb_info.monspecs.hfmin &&
999 hs <= fb_info.monspecs.hfmax) {
1000 acornfb_default_mode = modedb[i];
1001 break;
1002 }
1003 }
1004
1005 fb_info.screen_base = (char *)SCREEN_BASE;
1006 fb_info.fix.smem_start = SCREEN_START;
1007 current_par.using_vram = 0;
1008
1009
1010
1011
1012
1013
1014 if (vram_size && !current_par.dram_size) {
1015 size = vram_size;
1016 current_par.vram_half_sam = vram_size / 1024;
1017 current_par.using_vram = 1;
1018 } else if (current_par.dram_size)
1019 size = current_par.dram_size;
1020 else
1021 size = MAX_SIZE;
1022
1023
1024
1025
1026 if (size > MAX_SIZE)
1027 size = MAX_SIZE;
1028
1029 size = PAGE_ALIGN(size);
1030
1031 #if defined(HAS_VIDC20)
1032 if (!current_par.using_vram) {
1033 dma_addr_t handle;
1034 void *base;
1035
1036
1037
1038
1039
1040
1041 base = dma_alloc_wc(current_par.dev, size, &handle,
1042 GFP_KERNEL);
1043 if (base == NULL) {
1044 printk(KERN_ERR "acornfb: unable to allocate screen memory\n");
1045 return -ENOMEM;
1046 }
1047
1048 fb_info.screen_base = base;
1049 fb_info.fix.smem_start = handle;
1050 }
1051 #endif
1052 fb_info.fix.smem_len = size;
1053 current_par.palette_size = VIDC_PALETTE_SIZE;
1054
1055
1056
1057
1058
1059
1060 do {
1061 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
1062 ARRAY_SIZE(modedb),
1063 &acornfb_default_mode, DEFAULT_BPP);
1064
1065
1066
1067 if (rc == 1)
1068 break;
1069
1070 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0,
1071 &acornfb_default_mode, DEFAULT_BPP);
1072
1073
1074
1075 if (rc == 1)
1076 break;
1077
1078 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
1079 ARRAY_SIZE(modedb),
1080 &acornfb_default_mode, DEFAULT_BPP);
1081 if (rc)
1082 break;
1083
1084 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0,
1085 &acornfb_default_mode, DEFAULT_BPP);
1086 } while (0);
1087
1088
1089
1090
1091
1092 if (rc == 0) {
1093 printk("Acornfb: no valid mode found\n");
1094 return -EINVAL;
1095 }
1096
1097 h_sync = 1953125000 / fb_info.var.pixclock;
1098 h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin +
1099 fb_info.var.right_margin + fb_info.var.hsync_len);
1100 v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin +
1101 fb_info.var.lower_margin + fb_info.var.vsync_len);
1102
1103 printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, %d.%03dkHz, %dHz\n",
1104 fb_info.fix.smem_len / 1024,
1105 current_par.using_vram ? 'V' : 'D',
1106 VIDC_NAME, fb_info.var.xres, fb_info.var.yres,
1107 h_sync / 1000, h_sync % 1000, v_sync);
1108
1109 printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n",
1110 fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000,
1111 fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000,
1112 fb_info.monspecs.vfmin, fb_info.monspecs.vfmax,
1113 fb_info.monspecs.dpms ? ", DPMS" : "");
1114
1115 if (fb_set_var(&fb_info, &fb_info.var))
1116 printk(KERN_ERR "Acornfb: unable to set display parameters\n");
1117
1118 if (register_framebuffer(&fb_info) < 0)
1119 return -EINVAL;
1120 return 0;
1121 }
1122
1123 static struct platform_driver acornfb_driver = {
1124 .probe = acornfb_probe,
1125 .driver = {
1126 .name = "acornfb",
1127 },
1128 };
1129
1130 static int __init acornfb_init(void)
1131 {
1132 return platform_driver_register(&acornfb_driver);
1133 }
1134
1135 module_init(acornfb_init);
1136
1137 MODULE_AUTHOR("Russell King");
1138 MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");
1139 MODULE_LICENSE("GPL");