1 2 3#include <linux/module.h> 4#include <linux/kernel.h> 5#include <linux/errno.h> 6#include <linux/string.h> 7#include <linux/ctype.h> 8#include <linux/mm.h> 9#include <linux/init.h> 10#include <linux/fb.h> 11#include <linux/platform_device.h> 12#include <linux/dma-mapping.h> 13#include <linux/io.h> 14#include <linux/gfp.h> 15 16#include <mach/hardware.h> 17#include <asm/irq.h> 18#include <asm/mach-types.h> 19#include <asm/pgtable.h> 20 21#include "acornfb.h" 22 23/* 24 * VIDC machines can't do 16 or 32BPP modes. 25 */ 26#ifdef HAS_VIDC 27#undef FBCON_HAS_CFB16 28#undef FBCON_HAS_CFB32 29#endif 30 31/* 32 * Default resolution. 33 * NOTE that it has to be supported in the table towards 34 * the end of this file. 35 */ 36#define DEFAULT_XRES 640 37#define DEFAULT_YRES 480 38#define DEFAULT_BPP 4 39 40/* 41 * define this to debug the video mode selection 42 */ 43#undef DEBUG_MODE_SELECTION 44 45/* 46 * Translation from RISC OS monitor types to actual 47 * HSYNC and VSYNC frequency ranges. These are 48 * probably not right, but they're the best info I 49 * have. Allow 1% either way on the nominal for TVs. 50 */ 51#define NR_MONTYPES 6 52static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = { 53 { /* TV */ 54 .hfmin = 15469, 55 .hfmax = 15781, 56 .vfmin = 49, 57 .vfmax = 51, 58 }, { /* Multi Freq */ 59 .hfmin = 0, 60 .hfmax = 99999, 61 .vfmin = 0, 62 .vfmax = 199, 63 }, { /* Hi-res mono */ 64 .hfmin = 58608, 65 .hfmax = 58608, 66 .vfmin = 64, 67 .vfmax = 64, 68 }, { /* VGA */ 69 .hfmin = 30000, 70 .hfmax = 70000, 71 .vfmin = 60, 72 .vfmax = 60, 73 }, { /* SVGA */ 74 .hfmin = 30000, 75 .hfmax = 70000, 76 .vfmin = 56, 77 .vfmax = 75, 78 }, { 79 .hfmin = 30000, 80 .hfmax = 70000, 81 .vfmin = 60, 82 .vfmax = 60, 83 } 84}; 85 86static struct fb_info fb_info; 87static struct acornfb_par current_par; 88static struct vidc_timing current_vidc; 89 90extern unsigned int vram_size; /* set by setup.c */ 91 92#ifdef HAS_VIDC 93 94#define MAX_SIZE 480*1024 95 96/* CTL VIDC Actual 97 * 24.000 0 8.000 98 * 25.175 0 8.392 99 * 36.000 0 12.000 100 * 24.000 1 12.000 101 * 25.175 1 12.588 102 * 24.000 2 16.000 103 * 25.175 2 16.783 104 * 36.000 1 18.000 105 * 24.000 3 24.000 106 * 36.000 2 24.000 107 * 25.175 3 25.175 108 * 36.000 3 36.000 109 */ 110struct pixclock { 111 u_long min_clock; 112 u_long max_clock; 113 u_int vidc_ctl; 114 u_int vid_ctl; 115}; 116 117static struct pixclock arc_clocks[] = { 118 /* we allow +/-1% on these */ 119 { 123750, 126250, VIDC_CTRL_DIV3, VID_CTL_24MHz }, /* 8.000MHz */ 120 { 82500, 84167, VIDC_CTRL_DIV2, VID_CTL_24MHz }, /* 12.000MHz */ 121 { 61875, 63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz }, /* 16.000MHz */ 122 { 41250, 42083, VIDC_CTRL_DIV1, VID_CTL_24MHz }, /* 24.000MHz */ 123}; 124 125static struct pixclock * 126acornfb_valid_pixrate(struct fb_var_screeninfo *var) 127{ 128 u_long pixclock = var->pixclock; 129 u_int i; 130 131 if (!var->pixclock) 132 return NULL; 133 134 for (i = 0; i < ARRAY_SIZE(arc_clocks); i++) 135 if (pixclock > arc_clocks[i].min_clock && 136 pixclock < arc_clocks[i].max_clock) 137 return arc_clocks + i; 138 139 return NULL; 140} 141 142/* VIDC Rules: 143 * hcr : must be even (interlace, hcr/2 must be even) 144 * hswr : must be even 145 * hdsr : must be odd 146 * hder : must be odd 147 * 148 * vcr : must be odd 149 * vswr : >= 1 150 * vdsr : >= 1 151 * vder : >= vdsr 152 * if interlaced, then hcr/2 must be even 153 */ 154static void 155acornfb_set_timing(struct fb_var_screeninfo *var) 156{ 157 struct pixclock *pclk; 158 struct vidc_timing vidc; 159 u_int horiz_correction; 160 u_int sync_len, display_start, display_end, cycle; 161 u_int is_interlaced; 162 u_int vid_ctl, vidc_ctl; 163 u_int bandwidth; 164 165 memset(&vidc, 0, sizeof(vidc)); 166 167 pclk = acornfb_valid_pixrate(var); 168 vidc_ctl = pclk->vidc_ctl; 169 vid_ctl = pclk->vid_ctl; 170 171 bandwidth = var->pixclock * 8 / var->bits_per_pixel; 172 /* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */ 173 if (bandwidth > 143500) 174 vidc_ctl |= VIDC_CTRL_FIFO_3_7; 175 else if (bandwidth > 71750) 176 vidc_ctl |= VIDC_CTRL_FIFO_2_6; 177 else if (bandwidth > 35875) 178 vidc_ctl |= VIDC_CTRL_FIFO_1_5; 179 else 180 vidc_ctl |= VIDC_CTRL_FIFO_0_4; 181 182 switch (var->bits_per_pixel) { 183 case 1: 184 horiz_correction = 19; 185 vidc_ctl |= VIDC_CTRL_1BPP; 186 break; 187 188 case 2: 189 horiz_correction = 11; 190 vidc_ctl |= VIDC_CTRL_2BPP; 191 break; 192 193 case 4: 194 horiz_correction = 7; 195 vidc_ctl |= VIDC_CTRL_4BPP; 196 break; 197 198 default: 199 case 8: 200 horiz_correction = 5; 201 vidc_ctl |= VIDC_CTRL_8BPP; 202 break; 203 } 204 205 if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */ 206 vidc_ctl |= VIDC_CTRL_CSYNC; 207 else { 208 if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) 209 vid_ctl |= VID_CTL_HS_NHSYNC; 210 211 if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) 212 vid_ctl |= VID_CTL_VS_NVSYNC; 213 } 214 215 sync_len = var->hsync_len; 216 display_start = sync_len + var->left_margin; 217 display_end = display_start + var->xres; 218 cycle = display_end + var->right_margin; 219 220 /* if interlaced, then hcr/2 must be even */ 221 is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED; 222 223 if (is_interlaced) { 224 vidc_ctl |= VIDC_CTRL_INTERLACE; 225 if (cycle & 2) { 226 cycle += 2; 227 var->right_margin += 2; 228 } 229 } 230 231 vidc.h_cycle = (cycle - 2) / 2; 232 vidc.h_sync_width = (sync_len - 2) / 2; 233 vidc.h_border_start = (display_start - 1) / 2; 234 vidc.h_display_start = (display_start - horiz_correction) / 2; 235 vidc.h_display_end = (display_end - horiz_correction) / 2; 236 vidc.h_border_end = (display_end - 1) / 2; 237 vidc.h_interlace = (vidc.h_cycle + 1) / 2; 238 239 sync_len = var->vsync_len; 240 display_start = sync_len + var->upper_margin; 241 display_end = display_start + var->yres; 242 cycle = display_end + var->lower_margin; 243 244 if (is_interlaced) 245 cycle = (cycle - 3) / 2; 246 else 247 cycle = cycle - 1; 248 249 vidc.v_cycle = cycle; 250 vidc.v_sync_width = sync_len - 1; 251 vidc.v_border_start = display_start - 1; 252 vidc.v_display_start = vidc.v_border_start; 253 vidc.v_display_end = display_end - 1; 254 vidc.v_border_end = vidc.v_display_end; 255 256 if (machine_is_a5k()) 257 __raw_writeb(vid_ctl, IOEB_VID_CTL); 258 259 if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { 260 current_vidc = vidc; 261 262 vidc_writel(0xe0000000 | vidc_ctl); 263 vidc_writel(0x80000000 | (vidc.h_cycle << 14)); 264 vidc_writel(0x84000000 | (vidc.h_sync_width << 14)); 265 vidc_writel(0x88000000 | (vidc.h_border_start << 14)); 266 vidc_writel(0x8c000000 | (vidc.h_display_start << 14)); 267 vidc_writel(0x90000000 | (vidc.h_display_end << 14)); 268 vidc_writel(0x94000000 | (vidc.h_border_end << 14)); 269 vidc_writel(0x98000000); 270 vidc_writel(0x9c000000 | (vidc.h_interlace << 14)); 271 vidc_writel(0xa0000000 | (vidc.v_cycle << 14)); 272 vidc_writel(0xa4000000 | (vidc.v_sync_width << 14)); 273 vidc_writel(0xa8000000 | (vidc.v_border_start << 14)); 274 vidc_writel(0xac000000 | (vidc.v_display_start << 14)); 275 vidc_writel(0xb0000000 | (vidc.v_display_end << 14)); 276 vidc_writel(0xb4000000 | (vidc.v_border_end << 14)); 277 vidc_writel(0xb8000000); 278 vidc_writel(0xbc000000); 279 } 280#ifdef DEBUG_MODE_SELECTION 281 printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, 282 var->yres, var->bits_per_pixel); 283 printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle); 284 printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width); 285 printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start); 286 printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start); 287 printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end); 288 printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end); 289 printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace); 290 printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle); 291 printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width); 292 printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start); 293 printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start); 294 printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end); 295 printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end); 296 printk(KERN_DEBUG " VIDC Ctrl (E) : 0x%08X\n", vidc_ctl); 297 printk(KERN_DEBUG " IOEB Ctrl : 0x%08X\n", vid_ctl); 298#endif 299} 300 301static int 302acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 303 u_int trans, struct fb_info *info) 304{ 305 union palette pal; 306 307 if (regno >= current_par.palette_size) 308 return 1; 309 310 pal.p = 0; 311 pal.vidc.reg = regno; 312 pal.vidc.red = red >> 12; 313 pal.vidc.green = green >> 12; 314 pal.vidc.blue = blue >> 12; 315 316 current_par.palette[regno] = pal; 317 318 vidc_writel(pal.p); 319 320 return 0; 321} 322#endif 323 324#ifdef HAS_VIDC20 325#include <mach/acornfb.h> 326 327#define MAX_SIZE 2*1024*1024 328 329/* VIDC20 has a different set of rules from the VIDC: 330 * hcr : must be multiple of 4 331 * hswr : must be even 332 * hdsr : must be even 333 * hder : must be even 334 * vcr : >= 2, (interlace, must be odd) 335 * vswr : >= 1 336 * vdsr : >= 1 337 * vder : >= vdsr 338 */ 339static void acornfb_set_timing(struct fb_info *info) 340{ 341 struct fb_var_screeninfo *var = &info->var; 342 struct vidc_timing vidc; 343 u_int vcr, fsize; 344 u_int ext_ctl, dat_ctl; 345 u_int words_per_line; 346 347 memset(&vidc, 0, sizeof(vidc)); 348 349 vidc.h_sync_width = var->hsync_len - 8; 350 vidc.h_border_start = vidc.h_sync_width + var->left_margin + 8 - 12; 351 vidc.h_display_start = vidc.h_border_start + 12 - 18; 352 vidc.h_display_end = vidc.h_display_start + var->xres; 353 vidc.h_border_end = vidc.h_display_end + 18 - 12; 354 vidc.h_cycle = vidc.h_border_end + var->right_margin + 12 - 8; 355 vidc.h_interlace = vidc.h_cycle / 2; 356 vidc.v_sync_width = var->vsync_len - 1; 357 vidc.v_border_start = vidc.v_sync_width + var->upper_margin; 358 vidc.v_display_start = vidc.v_border_start; 359 vidc.v_display_end = vidc.v_display_start + var->yres; 360 vidc.v_border_end = vidc.v_display_end; 361 vidc.control = acornfb_default_control(); 362 363 vcr = var->vsync_len + var->upper_margin + var->yres + 364 var->lower_margin; 365 366 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { 367 vidc.v_cycle = (vcr - 3) / 2; 368 vidc.control |= VIDC20_CTRL_INT; 369 } else 370 vidc.v_cycle = vcr - 2; 371 372 switch (var->bits_per_pixel) { 373 case 1: vidc.control |= VIDC20_CTRL_1BPP; break; 374 case 2: vidc.control |= VIDC20_CTRL_2BPP; break; 375 case 4: vidc.control |= VIDC20_CTRL_4BPP; break; 376 default: 377 case 8: vidc.control |= VIDC20_CTRL_8BPP; break; 378 case 16: vidc.control |= VIDC20_CTRL_16BPP; break; 379 case 32: vidc.control |= VIDC20_CTRL_32BPP; break; 380 } 381 382 acornfb_vidc20_find_rates(&vidc, var); 383 fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1; 384 385 if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { 386 current_vidc = vidc; 387 388 vidc_writel(VIDC20_CTRL| vidc.control); 389 vidc_writel(0xd0000000 | vidc.pll_ctl); 390 vidc_writel(0x80000000 | vidc.h_cycle); 391 vidc_writel(0x81000000 | vidc.h_sync_width); 392 vidc_writel(0x82000000 | vidc.h_border_start); 393 vidc_writel(0x83000000 | vidc.h_display_start); 394 vidc_writel(0x84000000 | vidc.h_display_end); 395 vidc_writel(0x85000000 | vidc.h_border_end); 396 vidc_writel(0x86000000); 397 vidc_writel(0x87000000 | vidc.h_interlace); 398 vidc_writel(0x90000000 | vidc.v_cycle); 399 vidc_writel(0x91000000 | vidc.v_sync_width); 400 vidc_writel(0x92000000 | vidc.v_border_start); 401 vidc_writel(0x93000000 | vidc.v_display_start); 402 vidc_writel(0x94000000 | vidc.v_display_end); 403 vidc_writel(0x95000000 | vidc.v_border_end); 404 vidc_writel(0x96000000); 405 vidc_writel(0x97000000); 406 } 407 408 iomd_writel(fsize, IOMD_FSIZE); 409 410 ext_ctl = acornfb_default_econtrol(); 411 412 if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */ 413 ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC; 414 else { 415 if (var->sync & FB_SYNC_HOR_HIGH_ACT) 416 ext_ctl |= VIDC20_ECTL_HS_HSYNC; 417 else 418 ext_ctl |= VIDC20_ECTL_HS_NHSYNC; 419 420 if (var->sync & FB_SYNC_VERT_HIGH_ACT) 421 ext_ctl |= VIDC20_ECTL_VS_VSYNC; 422 else 423 ext_ctl |= VIDC20_ECTL_VS_NVSYNC; 424 } 425 426 vidc_writel(VIDC20_ECTL | ext_ctl); 427 428 words_per_line = var->xres * var->bits_per_pixel / 32; 429 430 if (current_par.using_vram && info->fix.smem_len == 2048*1024) 431 words_per_line /= 2; 432 433 /* RiscPC doesn't use the VIDC's VRAM control. */ 434 dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line; 435 436 /* The data bus width is dependent on both the type 437 * and amount of video memory. 438 * DRAM 32bit low 439 * 1MB VRAM 32bit 440 * 2MB VRAM 64bit 441 */ 442 if (current_par.using_vram && current_par.vram_half_sam == 2048) 443 dat_ctl |= VIDC20_DCTL_BUS_D63_0; 444 else 445 dat_ctl |= VIDC20_DCTL_BUS_D31_0; 446 447 vidc_writel(VIDC20_DCTL | dat_ctl); 448 449#ifdef DEBUG_MODE_SELECTION 450 printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, 451 var->yres, var->bits_per_pixel); 452 printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle); 453 printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width); 454 printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start); 455 printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start); 456 printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end); 457 printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end); 458 printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace); 459 printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle); 460 printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width); 461 printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start); 462 printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start); 463 printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end); 464 printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end); 465 printk(KERN_DEBUG " Ext Ctrl (C) : 0x%08X\n", ext_ctl); 466 printk(KERN_DEBUG " PLL Ctrl (D) : 0x%08X\n", vidc.pll_ctl); 467 printk(KERN_DEBUG " Ctrl (E) : 0x%08X\n", vidc.control); 468 printk(KERN_DEBUG " Data Ctrl (F) : 0x%08X\n", dat_ctl); 469 printk(KERN_DEBUG " Fsize : 0x%08X\n", fsize); 470#endif 471} 472 473/* 474 * We have to take note of the VIDC20's 16-bit palette here. 475 * The VIDC20 looks up a 16 bit pixel as follows: 476 * 477 * bits 111111 478 * 5432109876543210 479 * red ++++++++ (8 bits, 7 to 0) 480 * green ++++++++ (8 bits, 11 to 4) 481 * blue ++++++++ (8 bits, 15 to 8) 482 * 483 * We use a pixel which looks like: 484 * 485 * bits 111111 486 * 5432109876543210 487 * red +++++ (5 bits, 4 to 0) 488 * green +++++ (5 bits, 9 to 5) 489 * blue +++++ (5 bits, 14 to 10) 490 */ 491static int 492acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 493 u_int trans, struct fb_info *info) 494{ 495 union palette pal; 496 497 if (regno >= current_par.palette_size) 498 return 1; 499 500 if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 501 u32 pseudo_val; 502 503 pseudo_val = regno << info->var.red.offset; 504 pseudo_val |= regno << info->var.green.offset; 505 pseudo_val |= regno << info->var.blue.offset; 506 507 ((u32 *)info->pseudo_palette)[regno] = pseudo_val; 508 } 509 510 pal.p = 0; 511 pal.vidc20.red = red >> 8; 512 pal.vidc20.green = green >> 8; 513 pal.vidc20.blue = blue >> 8; 514 515 current_par.palette[regno] = pal; 516 517 if (info->var.bits_per_pixel == 16) { 518 int i; 519 520 pal.p = 0; 521 vidc_writel(0x10000000); 522 for (i = 0; i < 256; i += 1) { 523 pal.vidc20.red = current_par.palette[ i & 31].vidc20.red; 524 pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; 525 pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; 526 vidc_writel(pal.p); 527 /* Palette register pointer auto-increments */ 528 } 529 } else { 530 vidc_writel(0x10000000 | regno); 531 vidc_writel(pal.p); 532 } 533 534 return 0; 535} 536#endif 537 538/* 539 * Before selecting the timing parameters, adjust 540 * the resolution to fit the rules. 541 */ 542static int 543acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht) 544{ 545 u_int font_line_len, sam_size, min_size, size, nr_y; 546 547 /* xres must be even */ 548 var->xres = (var->xres + 1) & ~1; 549 550 /* 551 * We don't allow xres_virtual to differ from xres 552 */ 553 var->xres_virtual = var->xres; 554 var->xoffset = 0; 555 556 if (current_par.using_vram) 557 sam_size = current_par.vram_half_sam * 2; 558 else 559 sam_size = 16; 560 561 /* 562 * Now, find a value for yres_virtual which allows 563 * us to do ywrap scrolling. The value of 564 * yres_virtual must be such that the end of the 565 * displayable frame buffer must be aligned with 566 * the start of a font line. 567 */ 568 font_line_len = var->xres * var->bits_per_pixel * fontht / 8; 569 min_size = var->xres * var->yres * var->bits_per_pixel / 8; 570 571 /* 572 * If minimum screen size is greater than that we have 573 * available, reject it. 574 */ 575 if (min_size > info->fix.smem_len) 576 return -EINVAL; 577 578 /* Find int 'y', such that y * fll == s * sam < maxsize 579 * y = s * sam / fll; s = maxsize / sam 580 */ 581 for (size = info->fix.smem_len; 582 nr_y = size / font_line_len, min_size <= size; 583 size -= sam_size) { 584 if (nr_y * font_line_len == size) 585 break; 586 } 587 nr_y *= fontht; 588 589 if (var->accel_flags & FB_ACCELF_TEXT) { 590 if (min_size > size) { 591 /* 592 * failed, use ypan 593 */ 594 size = info->fix.smem_len; 595 var->yres_virtual = size / (font_line_len / fontht); 596 } else 597 var->yres_virtual = nr_y; 598 } else if (var->yres_virtual > nr_y) 599 var->yres_virtual = nr_y; 600 601 current_par.screen_end = info->fix.smem_start + size; 602 603 /* 604 * Fix yres & yoffset if needed. 605 */ 606 if (var->yres > var->yres_virtual) 607 var->yres = var->yres_virtual; 608 609 if (var->vmode & FB_VMODE_YWRAP) { 610 if (var->yoffset > var->yres_virtual) 611 var->yoffset = var->yres_virtual; 612 } else { 613 if (var->yoffset + var->yres > var->yres_virtual) 614 var->yoffset = var->yres_virtual - var->yres; 615 } 616 617 /* hsync_len must be even */ 618 var->hsync_len = (var->hsync_len + 1) & ~1; 619 620#ifdef HAS_VIDC 621 /* left_margin must be odd */ 622 if ((var->left_margin & 1) == 0) { 623 var->left_margin -= 1; 624 var->right_margin += 1; 625 } 626 627 /* right_margin must be odd */ 628 var->right_margin |= 1; 629#elif defined(HAS_VIDC20) 630 /* left_margin must be even */ 631 if (var->left_margin & 1) { 632 var->left_margin += 1; 633 var->right_margin -= 1; 634 } 635 636 /* right_margin must be even */ 637 if (var->right_margin & 1) 638 var->right_margin += 1; 639#endif 640 641 if (var->vsync_len < 1) 642 var->vsync_len = 1; 643 644 return 0; 645} 646 647static int 648acornfb_validate_timing(struct fb_var_screeninfo *var, 649 struct fb_monspecs *monspecs) 650{ 651 unsigned long hs, vs; 652 653 /* 654 * hs(Hz) = 10^12 / (pixclock * xtotal) 655 * vs(Hz) = hs(Hz) / ytotal 656 * 657 * No need to do long long divisions or anything 658 * like that if you factor it correctly 659 */ 660 hs = 1953125000 / var->pixclock; 661 hs = hs * 512 / 662 (var->xres + var->left_margin + var->right_margin + var->hsync_len); 663 vs = hs / 664 (var->yres + var->upper_margin + var->lower_margin + var->vsync_len); 665 666 return (vs >= monspecs->vfmin && vs <= monspecs->vfmax && 667 hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL; 668} 669 670static inline void 671acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) 672{ 673 u_int off = var->yoffset * info->fix.line_length; 674 675#if defined(HAS_MEMC) 676 memc_write(VDMA_INIT, off >> 2); 677#elif defined(HAS_IOMD) 678 iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT); 679#endif 680} 681 682static int 683acornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 684{ 685 u_int fontht; 686 int err; 687 688 fontht = 8; 689 690 var->red.msb_right = 0; 691 var->green.msb_right = 0; 692 var->blue.msb_right = 0; 693 var->transp.msb_right = 0; 694 695 switch (var->bits_per_pixel) { 696 case 1: case 2: case 4: case 8: 697 var->red.offset = 0; 698 var->red.length = var->bits_per_pixel; 699 var->green = var->red; 700 var->blue = var->red; 701 var->transp.offset = 0; 702 var->transp.length = 0; 703 break; 704 705#ifdef HAS_VIDC20 706 case 16: 707 var->red.offset = 0; 708 var->red.length = 5; 709 var->green.offset = 5; 710 var->green.length = 5; 711 var->blue.offset = 10; 712 var->blue.length = 5; 713 var->transp.offset = 15; 714 var->transp.length = 1; 715 break; 716 717 case 32: 718 var->red.offset = 0; 719 var->red.length = 8; 720 var->green.offset = 8; 721 var->green.length = 8; 722 var->blue.offset = 16; 723 var->blue.length = 8; 724 var->transp.offset = 24; 725 var->transp.length = 4; 726 break; 727#endif 728 default: 729 return -EINVAL; 730 } 731 732 /* 733 * Check to see if the pixel rate is valid. 734 */ 735 if (!acornfb_valid_pixrate(var)) 736 return -EINVAL; 737 738 /* 739 * Validate and adjust the resolution to 740 * match the video generator hardware. 741 */ 742 err = acornfb_adjust_timing(info, var, fontht); 743 if (err) 744 return err; 745 746 /* 747 * Validate the timing against the 748 * monitor hardware. 749 */ 750 return acornfb_validate_timing(var, &info->monspecs); 751} 752 753static int acornfb_set_par(struct fb_info *info) 754{ 755 switch (info->var.bits_per_pixel) { 756 case 1: 757 current_par.palette_size = 2; 758 info->fix.visual = FB_VISUAL_MONO10; 759 break; 760 case 2: 761 current_par.palette_size = 4; 762 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 763 break; 764 case 4: 765 current_par.palette_size = 16; 766 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 767 break; 768 case 8: 769 current_par.palette_size = VIDC_PALETTE_SIZE; 770#ifdef HAS_VIDC 771 info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; 772#else 773 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 774#endif 775 break; 776#ifdef HAS_VIDC20 777 case 16: 778 current_par.palette_size = 32; 779 info->fix.visual = FB_VISUAL_DIRECTCOLOR; 780 break; 781 case 32: 782 current_par.palette_size = VIDC_PALETTE_SIZE; 783 info->fix.visual = FB_VISUAL_DIRECTCOLOR; 784 break; 785#endif 786 default: 787 BUG(); 788 } 789 790 info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8; 791 792#if defined(HAS_MEMC) 793 { 794 unsigned long size = info->fix.smem_len - VDMA_XFERSIZE; 795 796 memc_write(VDMA_START, 0); 797 memc_write(VDMA_END, size >> 2); 798 } 799#elif defined(HAS_IOMD) 800 { 801 unsigned long start, size; 802 u_int control; 803 804 start = info->fix.smem_start; 805 size = current_par.screen_end; 806 807 if (current_par.using_vram) { 808 size -= current_par.vram_half_sam; 809 control = DMA_CR_E | (current_par.vram_half_sam / 256); 810 } else { 811 size -= 16; 812 control = DMA_CR_E | DMA_CR_D | 16; 813 } 814 815 iomd_writel(start, IOMD_VIDSTART); 816 iomd_writel(size, IOMD_VIDEND); 817 iomd_writel(control, IOMD_VIDCR); 818 } 819#endif 820 821 acornfb_update_dma(info, &info->var); 822 acornfb_set_timing(info); 823 824 return 0; 825} 826 827static int 828acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 829{ 830 u_int y_bottom = var->yoffset; 831 832 if (!(var->vmode & FB_VMODE_YWRAP)) 833 y_bottom += var->yres; 834 835 BUG_ON(y_bottom > var->yres_virtual); 836 837 acornfb_update_dma(info, var); 838 839 return 0; 840} 841 842static struct fb_ops acornfb_ops = { 843 .owner = THIS_MODULE, 844 .fb_check_var = acornfb_check_var, 845 .fb_set_par = acornfb_set_par, 846 .fb_setcolreg = acornfb_setcolreg, 847 .fb_pan_display = acornfb_pan_display, 848 .fb_fillrect = cfb_fillrect, 849 .fb_copyarea = cfb_copyarea, 850 .fb_imageblit = cfb_imageblit, 851}; 852 853/* 854 * Everything after here is initialisation!!! 855 */ 856static struct fb_videomode modedb[] __initdata = { 857 { /* 320x256 @ 50Hz */ 858 NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, 859 FB_SYNC_COMP_HIGH_ACT, 860 FB_VMODE_NONINTERLACED 861 }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */ 862 NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3, 863 0, 864 FB_VMODE_NONINTERLACED 865 }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */ 866 NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3, 867 0, 868 FB_VMODE_NONINTERLACED 869 }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */ 870 NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3, 871 0, 872 FB_VMODE_NONINTERLACED 873 }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */ 874 NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2, 875 0, 876 FB_VMODE_NONINTERLACED 877 }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */ 878 NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2, 879 0, 880 FB_VMODE_NONINTERLACED 881 }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */ 882 NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2, 883 0, 884 FB_VMODE_NONINTERLACED 885 }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */ 886 NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2, 887 0, 888 FB_VMODE_NONINTERLACED 889 }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */ 890 NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2, 891 0, 892 FB_VMODE_NONINTERLACED 893 }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */ 894 NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3, 895 0, 896 FB_VMODE_NONINTERLACED 897 }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */ 898 NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, 899 0, 900 FB_VMODE_NONINTERLACED 901 }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */ 902 NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3, 903 0, 904 FB_VMODE_NONINTERLACED 905 } 906}; 907 908static struct fb_videomode __initdata 909acornfb_default_mode = { 910 .name = NULL, 911 .refresh = 60, 912 .xres = 640, 913 .yres = 480, 914 .pixclock = 39722, 915 .left_margin = 56, 916 .right_margin = 16, 917 .upper_margin = 34, 918 .lower_margin = 9, 919 .hsync_len = 88, 920 .vsync_len = 2, 921 .sync = 0, 922 .vmode = FB_VMODE_NONINTERLACED 923}; 924 925static void __init acornfb_init_fbinfo(void) 926{ 927 static int first = 1; 928 929 if (!first) 930 return; 931 first = 0; 932 933 fb_info.fbops = &acornfb_ops; 934 fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; 935 fb_info.pseudo_palette = current_par.pseudo_palette; 936 937 strcpy(fb_info.fix.id, "Acorn"); 938 fb_info.fix.type = FB_TYPE_PACKED_PIXELS; 939 fb_info.fix.type_aux = 0; 940 fb_info.fix.xpanstep = 0; 941 fb_info.fix.ypanstep = 1; 942 fb_info.fix.ywrapstep = 1; 943 fb_info.fix.line_length = 0; 944 fb_info.fix.accel = FB_ACCEL_NONE; 945 946 /* 947 * setup initial parameters 948 */ 949 memset(&fb_info.var, 0, sizeof(fb_info.var)); 950 951#if defined(HAS_VIDC20) 952 fb_info.var.red.length = 8; 953 fb_info.var.transp.length = 4; 954#elif defined(HAS_VIDC) 955 fb_info.var.red.length = 4; 956 fb_info.var.transp.length = 1; 957#endif 958 fb_info.var.green = fb_info.var.red; 959 fb_info.var.blue = fb_info.var.red; 960 fb_info.var.nonstd = 0; 961 fb_info.var.activate = FB_ACTIVATE_NOW; 962 fb_info.var.height = -1; 963 fb_info.var.width = -1; 964 fb_info.var.vmode = FB_VMODE_NONINTERLACED; 965 fb_info.var.accel_flags = FB_ACCELF_TEXT; 966 967 current_par.dram_size = 0; 968 current_par.montype = -1; 969 current_par.dpms = 0; 970} 971 972/* 973 * setup acornfb options: 974 * 975 * mon:hmin-hmax:vmin-vmax:dpms:width:height 976 * Set monitor parameters: 977 * hmin = horizontal minimum frequency (Hz) 978 * hmax = horizontal maximum frequency (Hz) (optional) 979 * vmin = vertical minimum frequency (Hz) 980 * vmax = vertical maximum frequency (Hz) (optional) 981 * dpms = DPMS supported? (optional) 982 * width = width of picture in mm. (optional) 983 * height = height of picture in mm. (optional) 984 * 985 * montype:type 986 * Set RISC-OS style monitor type: 987 * 0 (or tv) - TV frequency 988 * 1 (or multi) - Multi frequency 989 * 2 (or hires) - Hi-res monochrome 990 * 3 (or vga) - VGA 991 * 4 (or svga) - SVGA 992 * auto, or option missing 993 * - try hardware detect 994 * 995 * dram:size 996 * Set the amount of DRAM to use for the frame buffer 997 * (even if you have VRAM). 998 * size can optionally be followed by 'M' or 'K' for 999 * MB or KB respectively. 1000 */ 1001static void __init 1002acornfb_parse_mon(char *opt) 1003{ 1004 char *p = opt; 1005 1006 current_par.montype = -2; 1007 1008 fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0); 1009 if (*p == '-') 1010 fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0); 1011 else 1012 fb_info.monspecs.hfmax = fb_info.monspecs.hfmin; 1013 1014 if (*p != ':') 1015 goto bad; 1016 1017 fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0); 1018 if (*p == '-') 1019 fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0); 1020 else 1021 fb_info.monspecs.vfmax = fb_info.monspecs.vfmin; 1022 1023 if (*p != ':') 1024 goto check_values; 1025 1026 fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0); 1027 1028 if (*p != ':') 1029 goto check_values; 1030 1031 fb_info.var.width = simple_strtoul(p + 1, &p, 0); 1032 1033 if (*p != ':') 1034 goto check_values; 1035 1036 fb_info.var.height = simple_strtoul(p + 1, NULL, 0); 1037 1038check_values: 1039 if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin || 1040 fb_info.monspecs.vfmax < fb_info.monspecs.vfmin) 1041 goto bad; 1042 return; 1043 1044bad: 1045 printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt); 1046 current_par.montype = -1; 1047} 1048 1049static void __init 1050acornfb_parse_montype(char *opt) 1051{ 1052 current_par.montype = -2; 1053 1054 if (strncmp(opt, "tv", 2) == 0) { 1055 opt += 2; 1056 current_par.montype = 0; 1057 } else if (strncmp(opt, "multi", 5) == 0) { 1058 opt += 5; 1059 current_par.montype = 1; 1060 } else if (strncmp(opt, "hires", 5) == 0) { 1061 opt += 5; 1062 current_par.montype = 2; 1063 } else if (strncmp(opt, "vga", 3) == 0) { 1064 opt += 3; 1065 current_par.montype = 3; 1066 } else if (strncmp(opt, "svga", 4) == 0) { 1067 opt += 4; 1068 current_par.montype = 4; 1069 } else if (strncmp(opt, "auto", 4) == 0) { 1070 opt += 4; 1071 current_par.montype = -1; 1072 } else if (isdigit(*opt)) 1073 current_par.montype = simple_strtoul(opt, &opt, 0); 1074 1075 if (current_par.montype == -2 || 1076 current_par.montype > NR_MONTYPES) { 1077 printk(KERN_ERR "acornfb: unknown monitor type: %s\n", 1078 opt); 1079 current_par.montype = -1; 1080 } else 1081 if (opt && *opt) { 1082 if (strcmp(opt, ",dpms") == 0) 1083 current_par.dpms = 1; 1084 else 1085 printk(KERN_ERR 1086 "acornfb: unknown monitor option: %s\n", 1087 opt); 1088 } 1089} 1090 1091static void __init 1092acornfb_parse_dram(char *opt) 1093{ 1094 unsigned int size; 1095 1096 size = simple_strtoul(opt, &opt, 0); 1097 1098 if (opt) { 1099 switch (*opt) { 1100 case 'M': 1101 case 'm': 1102 size *= 1024; 1103 case 'K': 1104 case 'k': 1105 size *= 1024; 1106 default: 1107 break; 1108 } 1109 } 1110 1111 current_par.dram_size = size; 1112} 1113 1114static struct options { 1115 char *name; 1116 void (*parse)(char *opt); 1117} opt_table[] __initdata = { 1118 { "mon", acornfb_parse_mon }, 1119 { "montype", acornfb_parse_montype }, 1120 { "dram", acornfb_parse_dram }, 1121 { NULL, NULL } 1122}; 1123 1124int __init 1125acornfb_setup(char *options) 1126{ 1127 struct options *optp; 1128 char *opt; 1129 1130 if (!options || !*options) 1131 return 0; 1132 1133 acornfb_init_fbinfo(); 1134 1135 while ((opt = strsep(&options, ",")) != NULL) { 1136 if (!*opt) 1137 continue; 1138 1139 for (optp = opt_table; optp->name; optp++) { 1140 int optlen; 1141 1142 optlen = strlen(optp->name); 1143 1144 if (strncmp(opt, optp->name, optlen) == 0 && 1145 opt[optlen] == ':') { 1146 optp->parse(opt + optlen + 1); 1147 break; 1148 } 1149 } 1150 1151 if (!optp->name) 1152 printk(KERN_ERR "acornfb: unknown parameter: %s\n", 1153 opt); 1154 } 1155 return 0; 1156} 1157 1158/* 1159 * Detect type of monitor connected 1160 * For now, we just assume SVGA 1161 */ 1162static int __init 1163acornfb_detect_monitortype(void) 1164{ 1165 return 4; 1166} 1167 1168/* 1169 * This enables the unused memory to be freed on older Acorn machines. 1170 * We are freeing memory on behalf of the architecture initialisation 1171 * code here. 1172 */ 1173static inline void 1174free_unused_pages(unsigned int virtual_start, unsigned int virtual_end) 1175{ 1176 int mb_freed = 0; 1177 1178 /* 1179 * Align addresses 1180 */ 1181 virtual_start = PAGE_ALIGN(virtual_start); 1182 virtual_end = PAGE_ALIGN(virtual_end); 1183 1184 while (virtual_start < virtual_end) { 1185 struct page *page; 1186 1187 /* 1188 * Clear page reserved bit, 1189 * set count to 1, and free 1190 * the page. 1191 */ 1192 page = virt_to_page(virtual_start); 1193 ClearPageReserved(page); 1194 init_page_count(page); 1195 free_page(virtual_start); 1196 1197 virtual_start += PAGE_SIZE; 1198 mb_freed += PAGE_SIZE / 1024; 1199 } 1200 1201 printk("acornfb: freed %dK memory\n", mb_freed); 1202} 1203 1204static int __devinit acornfb_probe(struct platform_device *dev) 1205{ 1206 unsigned long size; 1207 u_int h_sync, v_sync; 1208 int rc, i; 1209 char *option = NULL; 1210 1211 if (fb_get_options("acornfb", &option)) 1212 return -ENODEV; 1213 acornfb_setup(option); 1214 1215 acornfb_init_fbinfo(); 1216 1217 current_par.dev = &dev->dev; 1218 1219 if (current_par.montype == -1) 1220 current_par.montype = acornfb_detect_monitortype(); 1221 1222 if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) 1223 current_par.montype = 4; 1224 1225 if (current_par.montype >= 0) { 1226 fb_info.monspecs = monspecs[current_par.montype]; 1227 fb_info.monspecs.dpms = current_par.dpms; 1228 } 1229 1230 /* 1231 * Try to select a suitable default mode 1232 */ 1233 for (i = 0; i < ARRAY_SIZE(modedb); i++) { 1234 unsigned long hs; 1235 1236 hs = modedb[i].refresh * 1237 (modedb[i].yres + modedb[i].upper_margin + 1238 modedb[i].lower_margin + modedb[i].vsync_len); 1239 if (modedb[i].xres == DEFAULT_XRES && 1240 modedb[i].yres == DEFAULT_YRES && 1241 modedb[i].refresh >= fb_info.monspecs.vfmin && 1242 modedb[i].refresh <= fb_info.monspecs.vfmax && 1243 hs >= fb_info.monspecs.hfmin && 1244 hs <= fb_info.monspecs.hfmax) { 1245 acornfb_default_mode = modedb[i]; 1246 break; 1247 } 1248 } 1249 1250 fb_info.screen_base = (char *)SCREEN_BASE; 1251 fb_info.fix.smem_start = SCREEN_START; 1252 current_par.using_vram = 0; 1253 1254 /* 1255 * If vram_size is set, we are using VRAM in 1256 * a Risc PC. However, if the user has specified 1257 * an amount of DRAM then use that instead. 1258 */ 1259 if (vram_size && !current_par.dram_size) { 1260 size = vram_size; 1261 current_par.vram_half_sam = vram_size / 1024; 1262 current_par.using_vram = 1; 1263 } else if (current_par.dram_size) 1264 size = current_par.dram_size; 1265 else 1266 size = MAX_SIZE; 1267 1268 /* 1269 * Limit maximum screen size. 1270 */ 1271 if (size > MAX_SIZE) 1272 size = MAX_SIZE; 1273 1274 size = PAGE_ALIGN(size); 1275 1276#if defined(HAS_VIDC20) 1277 if (!current_par.using_vram) { 1278 dma_addr_t handle; 1279 void *base; 1280 1281 /* 1282 * RiscPC needs to allocate the DRAM memory 1283 * for the framebuffer if we are not using 1284 * VRAM. 1285 */ 1286 base = dma_alloc_writecombine(current_par.dev, size, &handle, 1287 GFP_KERNEL); 1288 if (base == NULL) { 1289 printk(KERN_ERR "acornfb: unable to allocate screen " 1290 "memory\n"); 1291 return -ENOMEM; 1292 } 1293 1294 fb_info.screen_base = base; 1295 fb_info.fix.smem_start = handle; 1296 } 1297#endif 1298#if defined(HAS_VIDC) 1299 /* 1300 * Archimedes/A5000 machines use a fixed address for their 1301 * framebuffers. Free unused pages 1302 */ 1303 free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); 1304#endif 1305 1306 fb_info.fix.smem_len = size; 1307 current_par.palette_size = VIDC_PALETTE_SIZE; 1308 1309 /* 1310 * Lookup the timing for this resolution. If we can't 1311 * find it, then we can't restore it if we change 1312 * the resolution, so we disable this feature. 1313 */ 1314 do { 1315 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, 1316 ARRAY_SIZE(modedb), 1317 &acornfb_default_mode, DEFAULT_BPP); 1318 /* 1319 * If we found an exact match, all ok. 1320 */ 1321 if (rc == 1) 1322 break; 1323 1324 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, 1325 &acornfb_default_mode, DEFAULT_BPP); 1326 /* 1327 * If we found an exact match, all ok. 1328 */ 1329 if (rc == 1) 1330 break; 1331 1332 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, 1333 ARRAY_SIZE(modedb), 1334 &acornfb_default_mode, DEFAULT_BPP); 1335 if (rc) 1336 break; 1337 1338 rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, 1339 &acornfb_default_mode, DEFAULT_BPP); 1340 } while (0); 1341 1342 /* 1343 * If we didn't find an exact match, try the 1344 * generic database. 1345 */ 1346 if (rc == 0) { 1347 printk("Acornfb: no valid mode found\n"); 1348 return -EINVAL; 1349 } 1350 1351 h_sync = 1953125000 / fb_info.var.pixclock; 1352 h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin + 1353 fb_info.var.right_margin + fb_info.var.hsync_len); 1354 v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin + 1355 fb_info.var.lower_margin + fb_info.var.vsync_len); 1356 1357 printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, " 1358 "%d.%03dkHz, %dHz\n", 1359 fb_info.fix.smem_len / 1024, 1360 current_par.using_vram ? 'V' : 'D', 1361 VIDC_NAME, fb_info.var.xres, fb_info.var.yres, 1362 h_sync / 1000, h_sync % 1000, v_sync); 1363 1364 printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n", 1365 fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000, 1366 fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000, 1367 fb_info.monspecs.vfmin, fb_info.monspecs.vfmax, 1368 fb_info.monspecs.dpms ? ", DPMS" : ""); 1369 1370 if (fb_set_var(&fb_info, &fb_info.var)) 1371 printk(KERN_ERR "Acornfb: unable to set display parameters\n"); 1372 1373 if (register_framebuffer(&fb_info) < 0) 1374 return -EINVAL; 1375 return 0; 1376} 1377 1378static struct platform_driver acornfb_driver = { 1379 .probe = acornfb_probe, 1380 .driver = { 1381 .name = "acornfb", 1382 }, 1383}; 1384 1385static int __init acornfb_init(void) 1386{ 1387 return platform_driver_register(&acornfb_driver); 1388} 1389 1390module_init(acornfb_init); 1391 1392MODULE_AUTHOR("Russell King"); 1393MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver"); 1394MODULE_LICENSE("GPL"); 1395