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