Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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