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