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.11-rc6 1409 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] = { 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[] = { 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 = { 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 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 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 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 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[] = { 1135 { "mon", acornfb_parse_mon }, 1136 { "montype", acornfb_parse_montype }, 1137 { "dram", acornfb_parse_dram }, 1138 { NULL, NULL } 1139}; 1140 1141static int 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 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 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");