Linux Audio

Check our new training course

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