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 *
acornfb_valid_pixrate(struct fb_var_screeninfo * var)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
acornfb_set_timing(struct fb_var_screeninfo * var)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;
180 	u_int bandwidth;
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
acornfb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int trans,struct fb_info * info)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  */
acornfb_set_timing(struct fb_info * info)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
acornfb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int trans,struct fb_info * info)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
acornfb_adjust_timing(struct fb_info * info,struct fb_var_screeninfo * var,u_int fontht)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
acornfb_validate_timing(struct fb_var_screeninfo * var,struct fb_monspecs * monspecs)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
acornfb_update_dma(struct fb_info * info,struct fb_var_screeninfo * var)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
acornfb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)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 
acornfb_set_par(struct fb_info * info)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 
816 		memc_write(VDMA_START, 0);
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
acornfb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)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 += var->yres;
854 
855 	BUG_ON(y_bottom > var->yres_virtual);
856 
857 	acornfb_update_dma(info, var);
858 
859 	return 0;
860 }
861 
862 static struct fb_ops acornfb_ops = {
863 	.owner		= THIS_MODULE,
864 	.fb_check_var	= acornfb_check_var,
865 	.fb_set_par	= acornfb_set_par,
866 	.fb_setcolreg	= acornfb_setcolreg,
867 	.fb_pan_display	= acornfb_pan_display,
868 	.fb_fillrect	= cfb_fillrect,
869 	.fb_copyarea	= cfb_copyarea,
870 	.fb_imageblit	= cfb_imageblit,
871 };
872 
873 /*
874  * Everything after here is initialisation!!!
875  */
876 static struct fb_videomode modedb[] __devinitdata = {
877 	{	/* 320x256 @ 50Hz */
878 		NULL, 50,  320,  256, 125000,  92,  62,  35, 19,  38, 2,
879 		FB_SYNC_COMP_HIGH_ACT,
880 		FB_VMODE_NONINTERLACED
881 	}, {	/* 640x250 @ 50Hz, 15.6 kHz hsync */
882 		NULL, 50,  640,  250,  62500, 185, 123,  38, 21,  76, 3,
883 		0,
884 		FB_VMODE_NONINTERLACED
885 	}, {	/* 640x256 @ 50Hz, 15.6 kHz hsync */
886 		NULL, 50,  640,  256,  62500, 185, 123,  35, 18,  76, 3,
887 		0,
888 		FB_VMODE_NONINTERLACED
889 	}, {	/* 640x512 @ 50Hz, 26.8 kHz hsync */
890 		NULL, 50,  640,  512,  41667, 113,  87,  18,  1,  56, 3,
891 		0,
892 		FB_VMODE_NONINTERLACED
893 	}, {	/* 640x250 @ 70Hz, 31.5 kHz hsync */
894 		NULL, 70,  640,  250,  39722,  48,  16, 109, 88,  96, 2,
895 		0,
896 		FB_VMODE_NONINTERLACED
897 	}, {	/* 640x256 @ 70Hz, 31.5 kHz hsync */
898 		NULL, 70,  640,  256,  39722,  48,  16, 106, 85,  96, 2,
899 		0,
900 		FB_VMODE_NONINTERLACED
901 	}, {	/* 640x352 @ 70Hz, 31.5 kHz hsync */
902 		NULL, 70,  640,  352,  39722,  48,  16,  58, 37,  96, 2,
903 		0,
904 		FB_VMODE_NONINTERLACED
905 	}, {	/* 640x480 @ 60Hz, 31.5 kHz hsync */
906 		NULL, 60,  640,  480,  39722,  48,  16,  32, 11,  96, 2,
907 		0,
908 		FB_VMODE_NONINTERLACED
909 	}, {	/* 800x600 @ 56Hz, 35.2 kHz hsync */
910 		NULL, 56,  800,  600,  27778, 101,  23,  22,  1, 100, 2,
911 		0,
912 		FB_VMODE_NONINTERLACED
913 	}, {	/* 896x352 @ 60Hz, 21.8 kHz hsync */
914 		NULL, 60,  896,  352,  41667,  59,  27,   9,  0, 118, 3,
915 		0,
916 		FB_VMODE_NONINTERLACED
917 	}, {	/* 1024x 768 @ 60Hz, 48.4 kHz hsync */
918 		NULL, 60, 1024,  768,  15385, 160,  24,  29,  3, 136, 6,
919 		0,
920 		FB_VMODE_NONINTERLACED
921 	}, {	/* 1280x1024 @ 60Hz, 63.8 kHz hsync */
922 		NULL, 60, 1280, 1024,   9090, 186,  96,  38,  1, 160, 3,
923 		0,
924 		FB_VMODE_NONINTERLACED
925 	}
926 };
927 
928 static struct fb_videomode acornfb_default_mode __devinitdata = {
929 	.name =		NULL,
930 	.refresh =	60,
931 	.xres =		640,
932 	.yres =		480,
933 	.pixclock =	39722,
934 	.left_margin =	56,
935 	.right_margin =	16,
936 	.upper_margin =	34,
937 	.lower_margin =	9,
938 	.hsync_len =	88,
939 	.vsync_len =	2,
940 	.sync =		0,
941 	.vmode =	FB_VMODE_NONINTERLACED
942 };
943 
acornfb_init_fbinfo(void)944 static void __devinit acornfb_init_fbinfo(void)
945 {
946 	static int first = 1;
947 
948 	if (!first)
949 		return;
950 	first = 0;
951 
952 	fb_info.fbops		= &acornfb_ops;
953 	fb_info.flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
954 	fb_info.pseudo_palette	= current_par.pseudo_palette;
955 
956 	strcpy(fb_info.fix.id, "Acorn");
957 	fb_info.fix.type	= FB_TYPE_PACKED_PIXELS;
958 	fb_info.fix.type_aux	= 0;
959 	fb_info.fix.xpanstep	= 0;
960 	fb_info.fix.ypanstep	= 1;
961 	fb_info.fix.ywrapstep	= 1;
962 	fb_info.fix.line_length	= 0;
963 	fb_info.fix.accel	= FB_ACCEL_NONE;
964 
965 	/*
966 	 * setup initial parameters
967 	 */
968 	memset(&fb_info.var, 0, sizeof(fb_info.var));
969 
970 #if defined(HAS_VIDC20)
971 	fb_info.var.red.length	   = 8;
972 	fb_info.var.transp.length  = 4;
973 #elif defined(HAS_VIDC)
974 	fb_info.var.red.length	   = 4;
975 	fb_info.var.transp.length  = 1;
976 #endif
977 	fb_info.var.green	   = fb_info.var.red;
978 	fb_info.var.blue	   = fb_info.var.red;
979 	fb_info.var.nonstd	   = 0;
980 	fb_info.var.activate	   = FB_ACTIVATE_NOW;
981 	fb_info.var.height	   = -1;
982 	fb_info.var.width	   = -1;
983 	fb_info.var.vmode	   = FB_VMODE_NONINTERLACED;
984 	fb_info.var.accel_flags	   = FB_ACCELF_TEXT;
985 
986 	current_par.dram_size	   = 0;
987 	current_par.montype	   = -1;
988 	current_par.dpms	   = 0;
989 }
990 
991 /*
992  * setup acornfb options:
993  *
994  *  mon:hmin-hmax:vmin-vmax:dpms:width:height
995  *	Set monitor parameters:
996  *		hmin   = horizontal minimum frequency (Hz)
997  *		hmax   = horizontal maximum frequency (Hz)	(optional)
998  *		vmin   = vertical minimum frequency (Hz)
999  *		vmax   = vertical maximum frequency (Hz)	(optional)
1000  *		dpms   = DPMS supported?			(optional)
1001  *		width  = width of picture in mm.		(optional)
1002  *		height = height of picture in mm.		(optional)
1003  *
1004  * montype:type
1005  *	Set RISC-OS style monitor type:
1006  *		0 (or tv)	- TV frequency
1007  *		1 (or multi)	- Multi frequency
1008  *		2 (or hires)	- Hi-res monochrome
1009  *		3 (or vga)	- VGA
1010  *		4 (or svga)	- SVGA
1011  *		auto, or option missing
1012  *				- try hardware detect
1013  *
1014  * dram:size
1015  *	Set the amount of DRAM to use for the frame buffer
1016  *	(even if you have VRAM).
1017  *	size can optionally be followed by 'M' or 'K' for
1018  *	MB or KB respectively.
1019  */
acornfb_parse_mon(char * opt)1020 static void __devinit acornfb_parse_mon(char *opt)
1021 {
1022 	char *p = opt;
1023 
1024 	current_par.montype = -2;
1025 
1026 	fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0);
1027 	if (*p == '-')
1028 		fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0);
1029 	else
1030 		fb_info.monspecs.hfmax = fb_info.monspecs.hfmin;
1031 
1032 	if (*p != ':')
1033 		goto bad;
1034 
1035 	fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0);
1036 	if (*p == '-')
1037 		fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0);
1038 	else
1039 		fb_info.monspecs.vfmax = fb_info.monspecs.vfmin;
1040 
1041 	if (*p != ':')
1042 		goto check_values;
1043 
1044 	fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0);
1045 
1046 	if (*p != ':')
1047 		goto check_values;
1048 
1049 	fb_info.var.width = simple_strtoul(p + 1, &p, 0);
1050 
1051 	if (*p != ':')
1052 		goto check_values;
1053 
1054 	fb_info.var.height = simple_strtoul(p + 1, NULL, 0);
1055 
1056 check_values:
1057 	if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin ||
1058 	    fb_info.monspecs.vfmax < fb_info.monspecs.vfmin)
1059 		goto bad;
1060 	return;
1061 
1062 bad:
1063 	printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt);
1064 	current_par.montype = -1;
1065 }
1066 
acornfb_parse_montype(char * opt)1067 static void __devinit acornfb_parse_montype(char *opt)
1068 {
1069 	current_par.montype = -2;
1070 
1071 	if (strncmp(opt, "tv", 2) == 0) {
1072 		opt += 2;
1073 		current_par.montype = 0;
1074 	} else if (strncmp(opt, "multi", 5) == 0) {
1075 		opt += 5;
1076 		current_par.montype = 1;
1077 	} else if (strncmp(opt, "hires", 5) == 0) {
1078 		opt += 5;
1079 		current_par.montype = 2;
1080 	} else if (strncmp(opt, "vga", 3) == 0) {
1081 		opt += 3;
1082 		current_par.montype = 3;
1083 	} else if (strncmp(opt, "svga", 4) == 0) {
1084 		opt += 4;
1085 		current_par.montype = 4;
1086 	} else if (strncmp(opt, "auto", 4) == 0) {
1087 		opt += 4;
1088 		current_par.montype = -1;
1089 	} else if (isdigit(*opt))
1090 		current_par.montype = simple_strtoul(opt, &opt, 0);
1091 
1092 	if (current_par.montype == -2 ||
1093 	    current_par.montype > NR_MONTYPES) {
1094 		printk(KERN_ERR "acornfb: unknown monitor type: %s\n",
1095 			opt);
1096 		current_par.montype = -1;
1097 	} else
1098 	if (opt && *opt) {
1099 		if (strcmp(opt, ",dpms") == 0)
1100 			current_par.dpms = 1;
1101 		else
1102 			printk(KERN_ERR
1103 			       "acornfb: unknown monitor option: %s\n",
1104 			       opt);
1105 	}
1106 }
1107 
acornfb_parse_dram(char * opt)1108 static void __devinit acornfb_parse_dram(char *opt)
1109 {
1110 	unsigned int size;
1111 
1112 	size = simple_strtoul(opt, &opt, 0);
1113 
1114 	if (opt) {
1115 		switch (*opt) {
1116 		case 'M':
1117 		case 'm':
1118 			size *= 1024;
1119 		case 'K':
1120 		case 'k':
1121 			size *= 1024;
1122 		default:
1123 			break;
1124 		}
1125 	}
1126 
1127 	current_par.dram_size = size;
1128 }
1129 
1130 static struct options {
1131 	char *name;
1132 	void (*parse)(char *opt);
1133 } opt_table[] __devinitdata = {
1134 	{ "mon",     acornfb_parse_mon     },
1135 	{ "montype", acornfb_parse_montype },
1136 	{ "dram",    acornfb_parse_dram    },
1137 	{ NULL, NULL }
1138 };
1139 
acornfb_setup(char * options)1140 static int __devinit acornfb_setup(char *options)
1141 {
1142 	struct options *optp;
1143 	char *opt;
1144 
1145 	if (!options || !*options)
1146 		return 0;
1147 
1148 	acornfb_init_fbinfo();
1149 
1150 	while ((opt = strsep(&options, ",")) != NULL) {
1151 		if (!*opt)
1152 			continue;
1153 
1154 		for (optp = opt_table; optp->name; optp++) {
1155 			int optlen;
1156 
1157 			optlen = strlen(optp->name);
1158 
1159 			if (strncmp(opt, optp->name, optlen) == 0 &&
1160 			    opt[optlen] == ':') {
1161 				optp->parse(opt + optlen + 1);
1162 				break;
1163 			}
1164 		}
1165 
1166 		if (!optp->name)
1167 			printk(KERN_ERR "acornfb: unknown parameter: %s\n",
1168 			       opt);
1169 	}
1170 	return 0;
1171 }
1172 
1173 /*
1174  * Detect type of monitor connected
1175  *  For now, we just assume SVGA
1176  */
acornfb_detect_monitortype(void)1177 static int __devinit acornfb_detect_monitortype(void)
1178 {
1179 	return 4;
1180 }
1181 
1182 /*
1183  * This enables the unused memory to be freed on older Acorn machines.
1184  * We are freeing memory on behalf of the architecture initialisation
1185  * code here.
1186  */
1187 static inline void
free_unused_pages(unsigned int virtual_start,unsigned int virtual_end)1188 free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
1189 {
1190 	int mb_freed = 0;
1191 
1192 	/*
1193 	 * Align addresses
1194 	 */
1195 	virtual_start = PAGE_ALIGN(virtual_start);
1196 	virtual_end = PAGE_ALIGN(virtual_end);
1197 
1198 	while (virtual_start < virtual_end) {
1199 		struct page *page;
1200 
1201 		/*
1202 		 * Clear page reserved bit,
1203 		 * set count to 1, and free
1204 		 * the page.
1205 		 */
1206 		page = virt_to_page(virtual_start);
1207 		ClearPageReserved(page);
1208 		init_page_count(page);
1209 		free_page(virtual_start);
1210 
1211 		virtual_start += PAGE_SIZE;
1212 		mb_freed += PAGE_SIZE / 1024;
1213 	}
1214 
1215 	printk("acornfb: freed %dK memory\n", mb_freed);
1216 }
1217 
acornfb_probe(struct platform_device * dev)1218 static int __devinit acornfb_probe(struct platform_device *dev)
1219 {
1220 	unsigned long size;
1221 	u_int h_sync, v_sync;
1222 	int rc, i;
1223 	char *option = NULL;
1224 
1225 	if (fb_get_options("acornfb", &option))
1226 		return -ENODEV;
1227 	acornfb_setup(option);
1228 
1229 	acornfb_init_fbinfo();
1230 
1231 	current_par.dev = &dev->dev;
1232 
1233 	if (current_par.montype == -1)
1234 		current_par.montype = acornfb_detect_monitortype();
1235 
1236 	if (current_par.montype == -1 || current_par.montype > NR_MONTYPES)
1237 		current_par.montype = 4;
1238 
1239 	if (current_par.montype >= 0) {
1240 		fb_info.monspecs = monspecs[current_par.montype];
1241 		fb_info.monspecs.dpms = current_par.dpms;
1242 	}
1243 
1244 	/*
1245 	 * Try to select a suitable default mode
1246 	 */
1247 	for (i = 0; i < ARRAY_SIZE(modedb); i++) {
1248 		unsigned long hs;
1249 
1250 		hs = modedb[i].refresh *
1251 		     (modedb[i].yres + modedb[i].upper_margin +
1252 		      modedb[i].lower_margin + modedb[i].vsync_len);
1253 		if (modedb[i].xres == DEFAULT_XRES &&
1254 		    modedb[i].yres == DEFAULT_YRES &&
1255 		    modedb[i].refresh >= fb_info.monspecs.vfmin &&
1256 		    modedb[i].refresh <= fb_info.monspecs.vfmax &&
1257 		    hs                >= fb_info.monspecs.hfmin &&
1258 		    hs                <= fb_info.monspecs.hfmax) {
1259 			acornfb_default_mode = modedb[i];
1260 			break;
1261 		}
1262 	}
1263 
1264 	fb_info.screen_base    = (char *)SCREEN_BASE;
1265 	fb_info.fix.smem_start = SCREEN_START;
1266 	current_par.using_vram = 0;
1267 
1268 	/*
1269 	 * If vram_size is set, we are using VRAM in
1270 	 * a Risc PC.  However, if the user has specified
1271 	 * an amount of DRAM then use that instead.
1272 	 */
1273 	if (vram_size && !current_par.dram_size) {
1274 		size = vram_size;
1275 		current_par.vram_half_sam = vram_size / 1024;
1276 		current_par.using_vram = 1;
1277 	} else if (current_par.dram_size)
1278 		size = current_par.dram_size;
1279 	else
1280 		size = MAX_SIZE;
1281 
1282 	/*
1283 	 * Limit maximum screen size.
1284 	 */
1285 	if (size > MAX_SIZE)
1286 		size = MAX_SIZE;
1287 
1288 	size = PAGE_ALIGN(size);
1289 
1290 #if defined(HAS_VIDC20)
1291 	if (!current_par.using_vram) {
1292 		dma_addr_t handle;
1293 		void *base;
1294 
1295 		/*
1296 		 * RiscPC needs to allocate the DRAM memory
1297 		 * for the framebuffer if we are not using
1298 		 * VRAM.
1299 		 */
1300 		base = dma_alloc_writecombine(current_par.dev, size, &handle,
1301 					      GFP_KERNEL);
1302 		if (base == NULL) {
1303 			printk(KERN_ERR "acornfb: unable to allocate screen "
1304 			       "memory\n");
1305 			return -ENOMEM;
1306 		}
1307 
1308 		fb_info.screen_base = base;
1309 		fb_info.fix.smem_start = handle;
1310 	}
1311 #endif
1312 #if defined(HAS_VIDC)
1313 	/*
1314 	 * Archimedes/A5000 machines use a fixed address for their
1315 	 * framebuffers.  Free unused pages
1316 	 */
1317 	free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
1318 #endif
1319 
1320 	fb_info.fix.smem_len = size;
1321 	current_par.palette_size   = VIDC_PALETTE_SIZE;
1322 
1323 	/*
1324 	 * Lookup the timing for this resolution.  If we can't
1325 	 * find it, then we can't restore it if we change
1326 	 * the resolution, so we disable this feature.
1327 	 */
1328 	do {
1329 		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
1330 				 ARRAY_SIZE(modedb),
1331 				 &acornfb_default_mode, DEFAULT_BPP);
1332 		/*
1333 		 * If we found an exact match, all ok.
1334 		 */
1335 		if (rc == 1)
1336 			break;
1337 
1338 		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0,
1339 				  &acornfb_default_mode, DEFAULT_BPP);
1340 		/*
1341 		 * If we found an exact match, all ok.
1342 		 */
1343 		if (rc == 1)
1344 			break;
1345 
1346 		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb,
1347 				 ARRAY_SIZE(modedb),
1348 				 &acornfb_default_mode, DEFAULT_BPP);
1349 		if (rc)
1350 			break;
1351 
1352 		rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0,
1353 				  &acornfb_default_mode, DEFAULT_BPP);
1354 	} while (0);
1355 
1356 	/*
1357 	 * If we didn't find an exact match, try the
1358 	 * generic database.
1359 	 */
1360 	if (rc == 0) {
1361 		printk("Acornfb: no valid mode found\n");
1362 		return -EINVAL;
1363 	}
1364 
1365 	h_sync = 1953125000 / fb_info.var.pixclock;
1366 	h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin +
1367 		 fb_info.var.right_margin + fb_info.var.hsync_len);
1368 	v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin +
1369 		 fb_info.var.lower_margin + fb_info.var.vsync_len);
1370 
1371 	printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, "
1372 		"%d.%03dkHz, %dHz\n",
1373 		fb_info.fix.smem_len / 1024,
1374 		current_par.using_vram ? 'V' : 'D',
1375 		VIDC_NAME, fb_info.var.xres, fb_info.var.yres,
1376 		h_sync / 1000, h_sync % 1000, v_sync);
1377 
1378 	printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n",
1379 		fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000,
1380 		fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000,
1381 		fb_info.monspecs.vfmin, fb_info.monspecs.vfmax,
1382 		fb_info.monspecs.dpms ? ", DPMS" : "");
1383 
1384 	if (fb_set_var(&fb_info, &fb_info.var))
1385 		printk(KERN_ERR "Acornfb: unable to set display parameters\n");
1386 
1387 	if (register_framebuffer(&fb_info) < 0)
1388 		return -EINVAL;
1389 	return 0;
1390 }
1391 
1392 static struct platform_driver acornfb_driver = {
1393 	.probe	= acornfb_probe,
1394 	.driver	= {
1395 		.name	= "acornfb",
1396 	},
1397 };
1398 
acornfb_init(void)1399 static int __init acornfb_init(void)
1400 {
1401 	return platform_driver_register(&acornfb_driver);
1402 }
1403 
1404 module_init(acornfb_init);
1405 
1406 MODULE_AUTHOR("Russell King");
1407 MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver");
1408 MODULE_LICENSE("GPL");
1409