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.15 1574 lines 43 kB view raw
1/* 2 * linux/drivers/video/sa1100fb.c 3 * 4 * Copyright (C) 1999 Eric A. Thomas 5 * Based on acornfb.c Copyright (C) Russell King. 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file COPYING in the main directory of this archive for 9 * more details. 10 * 11 * StrongARM 1100 LCD Controller Frame Buffer Driver 12 * 13 * Please direct your questions and comments on this driver to the following 14 * email address: 15 * 16 * linux-arm-kernel@lists.arm.linux.org.uk 17 * 18 * Clean patches should be sent to the ARM Linux Patch System. Please see the 19 * following web page for more information: 20 * 21 * http://www.arm.linux.org.uk/developer/patches/info.shtml 22 * 23 * Thank you. 24 * 25 * Known problems: 26 * - With the Neponset plugged into an Assabet, LCD powerdown 27 * doesn't work (LCD stays powered up). Therefore we shouldn't 28 * blank the screen. 29 * - We don't limit the CPU clock rate nor the mode selection 30 * according to the available SDRAM bandwidth. 31 * 32 * Other notes: 33 * - Linear grayscale palettes and the kernel. 34 * Such code does not belong in the kernel. The kernel frame buffer 35 * drivers do not expect a linear colourmap, but a colourmap based on 36 * the VT100 standard mapping. 37 * 38 * If your _userspace_ requires a linear colourmap, then the setup of 39 * such a colourmap belongs _in userspace_, not in the kernel. Code 40 * to set the colourmap correctly from user space has been sent to 41 * David Neuer. It's around 8 lines of C code, plus another 4 to 42 * detect if we are using grayscale. 43 * 44 * - The following must never be specified in a panel definition: 45 * LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL 46 * 47 * - The following should be specified: 48 * either LCCR0_Color or LCCR0_Mono 49 * either LCCR0_Sngl or LCCR0_Dual 50 * either LCCR0_Act or LCCR0_Pas 51 * either LCCR3_OutEnH or LCCD3_OutEnL 52 * either LCCR3_PixRsEdg or LCCR3_PixFlEdg 53 * either LCCR3_ACBsDiv or LCCR3_ACBsCntOff 54 * 55 * Code Status: 56 * 1999/04/01: 57 * - Driver appears to be working for Brutus 320x200x8bpp mode. Other 58 * resolutions are working, but only the 8bpp mode is supported. 59 * Changes need to be made to the palette encode and decode routines 60 * to support 4 and 16 bpp modes. 61 * Driver is not designed to be a module. The FrameBuffer is statically 62 * allocated since dynamic allocation of a 300k buffer cannot be 63 * guaranteed. 64 * 65 * 1999/06/17: 66 * - FrameBuffer memory is now allocated at run-time when the 67 * driver is initialized. 68 * 69 * 2000/04/10: Nicolas Pitre <nico@cam.org> 70 * - Big cleanup for dynamic selection of machine type at run time. 71 * 72 * 2000/07/19: Jamey Hicks <jamey@crl.dec.com> 73 * - Support for Bitsy aka Compaq iPAQ H3600 added. 74 * 75 * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com> 76 * Jeff Sutherland <jsutherland@accelent.com> 77 * - Resolved an issue caused by a change made to the Assabet's PLD 78 * earlier this year which broke the framebuffer driver for newer 79 * Phase 4 Assabets. Some other parameters were changed to optimize 80 * for the Sharp display. 81 * 82 * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp> 83 * - XP860 support added 84 * 85 * 2000/08/19: Mark Huang <mhuang@livetoy.com> 86 * - Allows standard options to be passed on the kernel command line 87 * for most common passive displays. 88 * 89 * 2000/08/29: 90 * - s/save_flags_cli/local_irq_save/ 91 * - remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller 92 * 93 * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl> 94 * - Updated LART stuff. Fixed some minor bugs. 95 * 96 * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw> 97 * - Pangolin support added 98 * 99 * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de> 100 * - Huw Webpanel support added 101 * 102 * 2000/11/23: Eric Peng <ericpeng@coventive.com> 103 * - Freebird add 104 * 105 * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com> 106 * Cliff Brake <cbrake@accelent.com> 107 * - Added PM callback 108 * 109 * 2001/05/26: <rmk@arm.linux.org.uk> 110 * - Fix 16bpp so that (a) we use the right colours rather than some 111 * totally random colour depending on what was in page 0, and (b) 112 * we don't de-reference a NULL pointer. 113 * - remove duplicated implementation of consistent_alloc() 114 * - convert dma address types to dma_addr_t 115 * - remove unused 'montype' stuff 116 * - remove redundant zero inits of init_var after the initial 117 * memzero. 118 * - remove allow_modeset (acornfb idea does not belong here) 119 * 120 * 2001/05/28: <rmk@arm.linux.org.uk> 121 * - massive cleanup - move machine dependent data into structures 122 * - I've left various #warnings in - if you see one, and know 123 * the hardware concerned, please get in contact with me. 124 * 125 * 2001/05/31: <rmk@arm.linux.org.uk> 126 * - Fix LCCR1 HSW value, fix all machine type specifications to 127 * keep values in line. (Please check your machine type specs) 128 * 129 * 2001/06/10: <rmk@arm.linux.org.uk> 130 * - Fiddle with the LCD controller from task context only; mainly 131 * so that we can run with interrupts on, and sleep. 132 * - Convert #warnings into #errors. No pain, no gain. ;) 133 * 134 * 2001/06/14: <rmk@arm.linux.org.uk> 135 * - Make the palette BPS value for 12bpp come out correctly. 136 * - Take notice of "greyscale" on any colour depth. 137 * - Make truecolor visuals use the RGB channel encoding information. 138 * 139 * 2001/07/02: <rmk@arm.linux.org.uk> 140 * - Fix colourmap problems. 141 * 142 * 2001/07/13: <abraham@2d3d.co.za> 143 * - Added support for the ICP LCD-Kit01 on LART. This LCD is 144 * manufactured by Prime View, model no V16C6448AB 145 * 146 * 2001/07/23: <rmk@arm.linux.org.uk> 147 * - Hand merge version from handhelds.org CVS tree. See patch 148 * notes for 595/1 for more information. 149 * - Drop 12bpp (it's 16bpp with different colour register mappings). 150 * - This hardware can not do direct colour. Therefore we don't 151 * support it. 152 * 153 * 2001/07/27: <rmk@arm.linux.org.uk> 154 * - Halve YRES on dual scan LCDs. 155 * 156 * 2001/08/22: <rmk@arm.linux.org.uk> 157 * - Add b/w iPAQ pixclock value. 158 * 159 * 2001/10/12: <rmk@arm.linux.org.uk> 160 * - Add patch 681/1 and clean up stork definitions. 161 */ 162 163#include <linux/config.h> 164#include <linux/module.h> 165#include <linux/kernel.h> 166#include <linux/sched.h> 167#include <linux/errno.h> 168#include <linux/string.h> 169#include <linux/interrupt.h> 170#include <linux/slab.h> 171#include <linux/fb.h> 172#include <linux/delay.h> 173#include <linux/init.h> 174#include <linux/ioport.h> 175#include <linux/cpufreq.h> 176#include <linux/platform_device.h> 177#include <linux/dma-mapping.h> 178 179#include <asm/hardware.h> 180#include <asm/io.h> 181#include <asm/irq.h> 182#include <asm/mach-types.h> 183#include <asm/uaccess.h> 184#include <asm/arch/assabet.h> 185#include <asm/arch/shannon.h> 186 187/* 188 * debugging? 189 */ 190#define DEBUG 0 191/* 192 * Complain if VAR is out of range. 193 */ 194#define DEBUG_VAR 1 195 196#undef ASSABET_PAL_VIDEO 197 198#include "sa1100fb.h" 199 200extern void (*sa1100fb_backlight_power)(int on); 201extern void (*sa1100fb_lcd_power)(int on); 202 203/* 204 * IMHO this looks wrong. In 8BPP, length should be 8. 205 */ 206static struct sa1100fb_rgb rgb_8 = { 207 .red = { .offset = 0, .length = 4, }, 208 .green = { .offset = 0, .length = 4, }, 209 .blue = { .offset = 0, .length = 4, }, 210 .transp = { .offset = 0, .length = 0, }, 211}; 212 213static struct sa1100fb_rgb def_rgb_16 = { 214 .red = { .offset = 11, .length = 5, }, 215 .green = { .offset = 5, .length = 6, }, 216 .blue = { .offset = 0, .length = 5, }, 217 .transp = { .offset = 0, .length = 0, }, 218}; 219 220#ifdef CONFIG_SA1100_ASSABET 221#ifndef ASSABET_PAL_VIDEO 222/* 223 * The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually 224 * takes an RGB666 signal, but we provide it with an RGB565 signal 225 * instead (def_rgb_16). 226 */ 227static struct sa1100fb_mach_info lq039q2ds54_info __initdata = { 228 .pixclock = 171521, .bpp = 16, 229 .xres = 320, .yres = 240, 230 231 .hsync_len = 5, .vsync_len = 1, 232 .left_margin = 61, .upper_margin = 3, 233 .right_margin = 9, .lower_margin = 0, 234 235 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 236 237 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 238 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), 239}; 240#else 241static struct sa1100fb_mach_info pal_info __initdata = { 242 .pixclock = 67797, .bpp = 16, 243 .xres = 640, .yres = 512, 244 245 .hsync_len = 64, .vsync_len = 6, 246 .left_margin = 125, .upper_margin = 70, 247 .right_margin = 115, .lower_margin = 36, 248 249 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 250 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), 251}; 252#endif 253#endif 254 255#ifdef CONFIG_SA1100_H3800 256static struct sa1100fb_mach_info h3800_info __initdata = { 257 .pixclock = 174757, .bpp = 16, 258 .xres = 320, .yres = 240, 259 260 .hsync_len = 3, .vsync_len = 3, 261 .left_margin = 12, .upper_margin = 10, 262 .right_margin = 17, .lower_margin = 1, 263 264 .cmap_static = 1, 265 266 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 267 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), 268}; 269#endif 270 271#ifdef CONFIG_SA1100_H3600 272static struct sa1100fb_mach_info h3600_info __initdata = { 273 .pixclock = 174757, .bpp = 16, 274 .xres = 320, .yres = 240, 275 276 .hsync_len = 3, .vsync_len = 3, 277 .left_margin = 12, .upper_margin = 10, 278 .right_margin = 17, .lower_margin = 1, 279 280 .cmap_static = 1, 281 282 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 283 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), 284}; 285 286static struct sa1100fb_rgb h3600_rgb_16 = { 287 .red = { .offset = 12, .length = 4, }, 288 .green = { .offset = 7, .length = 4, }, 289 .blue = { .offset = 1, .length = 4, }, 290 .transp = { .offset = 0, .length = 0, }, 291}; 292#endif 293 294#ifdef CONFIG_SA1100_H3100 295static struct sa1100fb_mach_info h3100_info __initdata = { 296 .pixclock = 406977, .bpp = 4, 297 .xres = 320, .yres = 240, 298 299 .hsync_len = 26, .vsync_len = 41, 300 .left_margin = 4, .upper_margin = 0, 301 .right_margin = 4, .lower_margin = 0, 302 303 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 304 .cmap_greyscale = 1, 305 .cmap_inverse = 1, 306 307 .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, 308 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), 309}; 310#endif 311 312#ifdef CONFIG_SA1100_COLLIE 313static struct sa1100fb_mach_info collie_info __initdata = { 314 .pixclock = 171521, .bpp = 16, 315 .xres = 320, .yres = 240, 316 317 .hsync_len = 5, .vsync_len = 1, 318 .left_margin = 11, .upper_margin = 2, 319 .right_margin = 30, .lower_margin = 0, 320 321 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 322 323 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 324 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), 325}; 326#endif 327 328#ifdef LART_GREY_LCD 329static struct sa1100fb_mach_info lart_grey_info __initdata = { 330 .pixclock = 150000, .bpp = 4, 331 .xres = 320, .yres = 240, 332 333 .hsync_len = 1, .vsync_len = 1, 334 .left_margin = 4, .upper_margin = 0, 335 .right_margin = 2, .lower_margin = 0, 336 337 .cmap_greyscale = 1, 338 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 339 340 .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, 341 .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), 342}; 343#endif 344#ifdef LART_COLOR_LCD 345static struct sa1100fb_mach_info lart_color_info __initdata = { 346 .pixclock = 150000, .bpp = 16, 347 .xres = 320, .yres = 240, 348 349 .hsync_len = 2, .vsync_len = 3, 350 .left_margin = 69, .upper_margin = 14, 351 .right_margin = 8, .lower_margin = 4, 352 353 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 354 .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), 355}; 356#endif 357#ifdef LART_VIDEO_OUT 358static struct sa1100fb_mach_info lart_video_info __initdata = { 359 .pixclock = 39721, .bpp = 16, 360 .xres = 640, .yres = 480, 361 362 .hsync_len = 95, .vsync_len = 2, 363 .left_margin = 40, .upper_margin = 32, 364 .right_margin = 24, .lower_margin = 11, 365 366 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 367 368 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 369 .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), 370}; 371#endif 372 373#ifdef LART_KIT01_LCD 374static struct sa1100fb_mach_info lart_kit01_info __initdata = { 375 .pixclock = 63291, .bpp = 16, 376 .xres = 640, .yres = 480, 377 378 .hsync_len = 64, .vsync_len = 3, 379 .left_margin = 122, .upper_margin = 45, 380 .right_margin = 10, .lower_margin = 10, 381 382 .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, 383 .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg 384}; 385#endif 386 387#ifdef CONFIG_SA1100_SHANNON 388static struct sa1100fb_mach_info shannon_info __initdata = { 389 .pixclock = 152500, .bpp = 8, 390 .xres = 640, .yres = 480, 391 392 .hsync_len = 4, .vsync_len = 3, 393 .left_margin = 2, .upper_margin = 0, 394 .right_margin = 1, .lower_margin = 0, 395 396 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 397 398 .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas, 399 .lccr3 = LCCR3_ACBsDiv(512), 400}; 401#endif 402 403 404 405static struct sa1100fb_mach_info * __init 406sa1100fb_get_machine_info(struct sa1100fb_info *fbi) 407{ 408 struct sa1100fb_mach_info *inf = NULL; 409 410 /* 411 * R G B T 412 * default {11,5}, { 5,6}, { 0,5}, { 0,0} 413 * h3600 {12,4}, { 7,4}, { 1,4}, { 0,0} 414 * freebird { 8,4}, { 4,4}, { 0,4}, {12,4} 415 */ 416#ifdef CONFIG_SA1100_ASSABET 417 if (machine_is_assabet()) { 418#ifndef ASSABET_PAL_VIDEO 419 inf = &lq039q2ds54_info; 420#else 421 inf = &pal_info; 422#endif 423 } 424#endif 425#ifdef CONFIG_SA1100_H3100 426 if (machine_is_h3100()) { 427 inf = &h3100_info; 428 } 429#endif 430#ifdef CONFIG_SA1100_H3600 431 if (machine_is_h3600()) { 432 inf = &h3600_info; 433 fbi->rgb[RGB_16] = &h3600_rgb_16; 434 } 435#endif 436#ifdef CONFIG_SA1100_H3800 437 if (machine_is_h3800()) { 438 inf = &h3800_info; 439 } 440#endif 441#ifdef CONFIG_SA1100_COLLIE 442 if (machine_is_collie()) { 443 inf = &collie_info; 444 } 445#endif 446#ifdef CONFIG_SA1100_LART 447 if (machine_is_lart()) { 448#ifdef LART_GREY_LCD 449 inf = &lart_grey_info; 450#endif 451#ifdef LART_COLOR_LCD 452 inf = &lart_color_info; 453#endif 454#ifdef LART_VIDEO_OUT 455 inf = &lart_video_info; 456#endif 457#ifdef LART_KIT01_LCD 458 inf = &lart_kit01_info; 459#endif 460 } 461#endif 462#ifdef CONFIG_SA1100_SHANNON 463 if (machine_is_shannon()) { 464 inf = &shannon_info; 465 } 466#endif 467 return inf; 468} 469 470static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *); 471static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state); 472 473static inline void sa1100fb_schedule_work(struct sa1100fb_info *fbi, u_int state) 474{ 475 unsigned long flags; 476 477 local_irq_save(flags); 478 /* 479 * We need to handle two requests being made at the same time. 480 * There are two important cases: 481 * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) 482 * We must perform the unblanking, which will do our REENABLE for us. 483 * 2. When we are blanking, but immediately unblank before we have 484 * blanked. We do the "REENABLE" thing here as well, just to be sure. 485 */ 486 if (fbi->task_state == C_ENABLE && state == C_REENABLE) 487 state = (u_int) -1; 488 if (fbi->task_state == C_DISABLE && state == C_ENABLE) 489 state = C_REENABLE; 490 491 if (state != (u_int)-1) { 492 fbi->task_state = state; 493 schedule_work(&fbi->task); 494 } 495 local_irq_restore(flags); 496} 497 498static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) 499{ 500 chan &= 0xffff; 501 chan >>= 16 - bf->length; 502 return chan << bf->offset; 503} 504 505/* 506 * Convert bits-per-pixel to a hardware palette PBS value. 507 */ 508static inline u_int palette_pbs(struct fb_var_screeninfo *var) 509{ 510 int ret = 0; 511 switch (var->bits_per_pixel) { 512 case 4: ret = 0 << 12; break; 513 case 8: ret = 1 << 12; break; 514 case 16: ret = 2 << 12; break; 515 } 516 return ret; 517} 518 519static int 520sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, 521 u_int trans, struct fb_info *info) 522{ 523 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 524 u_int val, ret = 1; 525 526 if (regno < fbi->palette_size) { 527 val = ((red >> 4) & 0xf00); 528 val |= ((green >> 8) & 0x0f0); 529 val |= ((blue >> 12) & 0x00f); 530 531 if (regno == 0) 532 val |= palette_pbs(&fbi->fb.var); 533 534 fbi->palette_cpu[regno] = val; 535 ret = 0; 536 } 537 return ret; 538} 539 540static int 541sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 542 u_int trans, struct fb_info *info) 543{ 544 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 545 unsigned int val; 546 int ret = 1; 547 548 /* 549 * If inverse mode was selected, invert all the colours 550 * rather than the register number. The register number 551 * is what you poke into the framebuffer to produce the 552 * colour you requested. 553 */ 554 if (fbi->cmap_inverse) { 555 red = 0xffff - red; 556 green = 0xffff - green; 557 blue = 0xffff - blue; 558 } 559 560 /* 561 * If greyscale is true, then we convert the RGB value 562 * to greyscale no mater what visual we are using. 563 */ 564 if (fbi->fb.var.grayscale) 565 red = green = blue = (19595 * red + 38470 * green + 566 7471 * blue) >> 16; 567 568 switch (fbi->fb.fix.visual) { 569 case FB_VISUAL_TRUECOLOR: 570 /* 571 * 12 or 16-bit True Colour. We encode the RGB value 572 * according to the RGB bitfield information. 573 */ 574 if (regno < 16) { 575 u32 *pal = fbi->fb.pseudo_palette; 576 577 val = chan_to_field(red, &fbi->fb.var.red); 578 val |= chan_to_field(green, &fbi->fb.var.green); 579 val |= chan_to_field(blue, &fbi->fb.var.blue); 580 581 pal[regno] = val; 582 ret = 0; 583 } 584 break; 585 586 case FB_VISUAL_STATIC_PSEUDOCOLOR: 587 case FB_VISUAL_PSEUDOCOLOR: 588 ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info); 589 break; 590 } 591 592 return ret; 593} 594 595#ifdef CONFIG_CPU_FREQ 596/* 597 * sa1100fb_display_dma_period() 598 * Calculate the minimum period (in picoseconds) between two DMA 599 * requests for the LCD controller. If we hit this, it means we're 600 * doing nothing but LCD DMA. 601 */ 602static inline unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var) 603{ 604 /* 605 * Period = pixclock * bits_per_byte * bytes_per_transfer 606 * / memory_bits_per_pixel; 607 */ 608 return var->pixclock * 8 * 16 / var->bits_per_pixel; 609} 610#endif 611 612/* 613 * sa1100fb_check_var(): 614 * Round up in the following order: bits_per_pixel, xres, 615 * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, 616 * bitfields, horizontal timing, vertical timing. 617 */ 618static int 619sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 620{ 621 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 622 int rgbidx; 623 624 if (var->xres < MIN_XRES) 625 var->xres = MIN_XRES; 626 if (var->yres < MIN_YRES) 627 var->yres = MIN_YRES; 628 if (var->xres > fbi->max_xres) 629 var->xres = fbi->max_xres; 630 if (var->yres > fbi->max_yres) 631 var->yres = fbi->max_yres; 632 var->xres_virtual = max(var->xres_virtual, var->xres); 633 var->yres_virtual = max(var->yres_virtual, var->yres); 634 635 DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); 636 switch (var->bits_per_pixel) { 637 case 4: 638 rgbidx = RGB_8; 639 break; 640 case 8: 641 rgbidx = RGB_8; 642 break; 643 case 16: 644 rgbidx = RGB_16; 645 break; 646 default: 647 return -EINVAL; 648 } 649 650 /* 651 * Copy the RGB parameters for this display 652 * from the machine specific parameters. 653 */ 654 var->red = fbi->rgb[rgbidx]->red; 655 var->green = fbi->rgb[rgbidx]->green; 656 var->blue = fbi->rgb[rgbidx]->blue; 657 var->transp = fbi->rgb[rgbidx]->transp; 658 659 DPRINTK("RGBT length = %d:%d:%d:%d\n", 660 var->red.length, var->green.length, var->blue.length, 661 var->transp.length); 662 663 DPRINTK("RGBT offset = %d:%d:%d:%d\n", 664 var->red.offset, var->green.offset, var->blue.offset, 665 var->transp.offset); 666 667#ifdef CONFIG_CPU_FREQ 668 printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n", 669 sa1100fb_display_dma_period(var), 670 cpufreq_get(smp_processor_id())); 671#endif 672 673 return 0; 674} 675 676static inline void sa1100fb_set_truecolor(u_int is_true_color) 677{ 678 if (machine_is_assabet()) { 679#if 1 // phase 4 or newer Assabet's 680 if (is_true_color) 681 ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); 682 else 683 ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); 684#else 685 // older Assabet's 686 if (is_true_color) 687 ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB); 688 else 689 ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); 690#endif 691 } 692} 693 694/* 695 * sa1100fb_set_par(): 696 * Set the user defined part of the display for the specified console 697 */ 698static int sa1100fb_set_par(struct fb_info *info) 699{ 700 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 701 struct fb_var_screeninfo *var = &info->var; 702 unsigned long palette_mem_size; 703 704 DPRINTK("set_par\n"); 705 706 if (var->bits_per_pixel == 16) 707 fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; 708 else if (!fbi->cmap_static) 709 fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; 710 else { 711 /* 712 * Some people have weird ideas about wanting static 713 * pseudocolor maps. I suspect their user space 714 * applications are broken. 715 */ 716 fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; 717 } 718 719 fbi->fb.fix.line_length = var->xres_virtual * 720 var->bits_per_pixel / 8; 721 fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16; 722 723 palette_mem_size = fbi->palette_size * sizeof(u16); 724 725 DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); 726 727 fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); 728 fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; 729 730 /* 731 * Set (any) board control register to handle new color depth 732 */ 733 sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); 734 sa1100fb_activate_var(var, fbi); 735 736 return 0; 737} 738 739#if 0 740static int 741sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, 742 struct fb_info *info) 743{ 744 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 745 746 /* 747 * Make sure the user isn't doing something stupid. 748 */ 749 if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static)) 750 return -EINVAL; 751 752 return gen_set_cmap(cmap, kspc, con, info); 753} 754#endif 755 756/* 757 * Formal definition of the VESA spec: 758 * On 759 * This refers to the state of the display when it is in full operation 760 * Stand-By 761 * This defines an optional operating state of minimal power reduction with 762 * the shortest recovery time 763 * Suspend 764 * This refers to a level of power management in which substantial power 765 * reduction is achieved by the display. The display can have a longer 766 * recovery time from this state than from the Stand-by state 767 * Off 768 * This indicates that the display is consuming the lowest level of power 769 * and is non-operational. Recovery from this state may optionally require 770 * the user to manually power on the monitor 771 * 772 * Now, the fbdev driver adds an additional state, (blank), where they 773 * turn off the video (maybe by colormap tricks), but don't mess with the 774 * video itself: think of it semantically between on and Stand-By. 775 * 776 * So here's what we should do in our fbdev blank routine: 777 * 778 * VESA_NO_BLANKING (mode 0) Video on, front/back light on 779 * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off 780 * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off 781 * VESA_POWERDOWN (mode 3) Video off, front/back light off 782 * 783 * This will match the matrox implementation. 784 */ 785/* 786 * sa1100fb_blank(): 787 * Blank the display by setting all palette values to zero. Note, the 788 * 12 and 16 bpp modes don't really use the palette, so this will not 789 * blank the display in all modes. 790 */ 791static int sa1100fb_blank(int blank, struct fb_info *info) 792{ 793 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 794 int i; 795 796 DPRINTK("sa1100fb_blank: blank=%d\n", blank); 797 798 switch (blank) { 799 case FB_BLANK_POWERDOWN: 800 case FB_BLANK_VSYNC_SUSPEND: 801 case FB_BLANK_HSYNC_SUSPEND: 802 case FB_BLANK_NORMAL: 803 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || 804 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) 805 for (i = 0; i < fbi->palette_size; i++) 806 sa1100fb_setpalettereg(i, 0, 0, 0, 0, info); 807 sa1100fb_schedule_work(fbi, C_DISABLE); 808 break; 809 810 case FB_BLANK_UNBLANK: 811 if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || 812 fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) 813 fb_set_cmap(&fbi->fb.cmap, info); 814 sa1100fb_schedule_work(fbi, C_ENABLE); 815 } 816 return 0; 817} 818 819static int sa1100fb_mmap(struct fb_info *info, struct file *file, 820 struct vm_area_struct *vma) 821{ 822 struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; 823 unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT; 824 825 if (off < info->fix.smem_len) { 826 vma->vm_pgoff += 1; /* skip over the palette */ 827 return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, 828 fbi->map_dma, fbi->map_size); 829 } 830 831 start = info->fix.mmio_start; 832 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); 833 834 if ((vma->vm_end - vma->vm_start + off) > len) 835 return -EINVAL; 836 837 off += start & PAGE_MASK; 838 vma->vm_pgoff = off >> PAGE_SHIFT; 839 vma->vm_flags |= VM_IO; 840 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 841 return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, 842 vma->vm_end - vma->vm_start, 843 vma->vm_page_prot); 844} 845 846static struct fb_ops sa1100fb_ops = { 847 .owner = THIS_MODULE, 848 .fb_check_var = sa1100fb_check_var, 849 .fb_set_par = sa1100fb_set_par, 850// .fb_set_cmap = sa1100fb_set_cmap, 851 .fb_setcolreg = sa1100fb_setcolreg, 852 .fb_fillrect = cfb_fillrect, 853 .fb_copyarea = cfb_copyarea, 854 .fb_imageblit = cfb_imageblit, 855 .fb_blank = sa1100fb_blank, 856 .fb_mmap = sa1100fb_mmap, 857}; 858 859/* 860 * Calculate the PCD value from the clock rate (in picoseconds). 861 * We take account of the PPCR clock setting. 862 */ 863static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock) 864{ 865 unsigned int pcd = cpuclock / 100; 866 867 pcd *= pixclock; 868 pcd /= 10000000; 869 870 return pcd + 1; /* make up for integer math truncations */ 871} 872 873/* 874 * sa1100fb_activate_var(): 875 * Configures LCD Controller based on entries in var parameter. Settings are 876 * only written to the controller if changes were made. 877 */ 878static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) 879{ 880 struct sa1100fb_lcd_reg new_regs; 881 u_int half_screen_size, yres, pcd; 882 u_long flags; 883 884 DPRINTK("Configuring SA1100 LCD\n"); 885 886 DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n", 887 var->xres, var->hsync_len, 888 var->left_margin, var->right_margin); 889 DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n", 890 var->yres, var->vsync_len, 891 var->upper_margin, var->lower_margin); 892 893#if DEBUG_VAR 894 if (var->xres < 16 || var->xres > 1024) 895 printk(KERN_ERR "%s: invalid xres %d\n", 896 fbi->fb.fix.id, var->xres); 897 if (var->hsync_len < 1 || var->hsync_len > 64) 898 printk(KERN_ERR "%s: invalid hsync_len %d\n", 899 fbi->fb.fix.id, var->hsync_len); 900 if (var->left_margin < 1 || var->left_margin > 255) 901 printk(KERN_ERR "%s: invalid left_margin %d\n", 902 fbi->fb.fix.id, var->left_margin); 903 if (var->right_margin < 1 || var->right_margin > 255) 904 printk(KERN_ERR "%s: invalid right_margin %d\n", 905 fbi->fb.fix.id, var->right_margin); 906 if (var->yres < 1 || var->yres > 1024) 907 printk(KERN_ERR "%s: invalid yres %d\n", 908 fbi->fb.fix.id, var->yres); 909 if (var->vsync_len < 1 || var->vsync_len > 64) 910 printk(KERN_ERR "%s: invalid vsync_len %d\n", 911 fbi->fb.fix.id, var->vsync_len); 912 if (var->upper_margin < 0 || var->upper_margin > 255) 913 printk(KERN_ERR "%s: invalid upper_margin %d\n", 914 fbi->fb.fix.id, var->upper_margin); 915 if (var->lower_margin < 0 || var->lower_margin > 255) 916 printk(KERN_ERR "%s: invalid lower_margin %d\n", 917 fbi->fb.fix.id, var->lower_margin); 918#endif 919 920 new_regs.lccr0 = fbi->lccr0 | 921 LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | 922 LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); 923 924 new_regs.lccr1 = 925 LCCR1_DisWdth(var->xres) + 926 LCCR1_HorSnchWdth(var->hsync_len) + 927 LCCR1_BegLnDel(var->left_margin) + 928 LCCR1_EndLnDel(var->right_margin); 929 930 /* 931 * If we have a dual scan LCD, then we need to halve 932 * the YRES parameter. 933 */ 934 yres = var->yres; 935 if (fbi->lccr0 & LCCR0_Dual) 936 yres /= 2; 937 938 new_regs.lccr2 = 939 LCCR2_DisHght(yres) + 940 LCCR2_VrtSnchWdth(var->vsync_len) + 941 LCCR2_BegFrmDel(var->upper_margin) + 942 LCCR2_EndFrmDel(var->lower_margin); 943 944 pcd = get_pcd(var->pixclock, cpufreq_get(0)); 945 new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 | 946 (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | 947 (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); 948 949 DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0); 950 DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1); 951 DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2); 952 DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3); 953 954 half_screen_size = var->bits_per_pixel; 955 half_screen_size = half_screen_size * var->xres * var->yres / 16; 956 957 /* Update shadow copy atomically */ 958 local_irq_save(flags); 959 fbi->dbar1 = fbi->palette_dma; 960 fbi->dbar2 = fbi->screen_dma + half_screen_size; 961 962 fbi->reg_lccr0 = new_regs.lccr0; 963 fbi->reg_lccr1 = new_regs.lccr1; 964 fbi->reg_lccr2 = new_regs.lccr2; 965 fbi->reg_lccr3 = new_regs.lccr3; 966 local_irq_restore(flags); 967 968 /* 969 * Only update the registers if the controller is enabled 970 * and something has changed. 971 */ 972 if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || 973 (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || 974 (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2)) 975 sa1100fb_schedule_work(fbi, C_REENABLE); 976 977 return 0; 978} 979 980/* 981 * NOTE! The following functions are purely helpers for set_ctrlr_state. 982 * Do not call them directly; set_ctrlr_state does the correct serialisation 983 * to ensure that things happen in the right way 100% of time time. 984 * -- rmk 985 */ 986static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on) 987{ 988 DPRINTK("backlight o%s\n", on ? "n" : "ff"); 989 990 if (sa1100fb_backlight_power) 991 sa1100fb_backlight_power(on); 992} 993 994static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on) 995{ 996 DPRINTK("LCD power o%s\n", on ? "n" : "ff"); 997 998 if (sa1100fb_lcd_power) 999 sa1100fb_lcd_power(on); 1000} 1001 1002static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) 1003{ 1004 u_int mask = 0; 1005 1006 /* 1007 * Enable GPIO<9:2> for LCD use if: 1008 * 1. Active display, or 1009 * 2. Color Dual Passive display 1010 * 1011 * see table 11.8 on page 11-27 in the SA1100 manual 1012 * -- Erik. 1013 * 1014 * SA1110 spec update nr. 25 says we can and should 1015 * clear LDD15 to 12 for 4 or 8bpp modes with active 1016 * panels. 1017 */ 1018 if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color && 1019 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) { 1020 mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8; 1021 1022 if (fbi->fb.var.bits_per_pixel > 8 || 1023 (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual) 1024 mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12; 1025 1026 } 1027 1028 if (mask) { 1029 GPDR |= mask; 1030 GAFR |= mask; 1031 } 1032} 1033 1034static void sa1100fb_enable_controller(struct sa1100fb_info *fbi) 1035{ 1036 DPRINTK("Enabling LCD controller\n"); 1037 1038 /* 1039 * Make sure the mode bits are present in the first palette entry 1040 */ 1041 fbi->palette_cpu[0] &= 0xcfff; 1042 fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var); 1043 1044 /* Sequence from 11.7.10 */ 1045 LCCR3 = fbi->reg_lccr3; 1046 LCCR2 = fbi->reg_lccr2; 1047 LCCR1 = fbi->reg_lccr1; 1048 LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN; 1049 DBAR1 = fbi->dbar1; 1050 DBAR2 = fbi->dbar2; 1051 LCCR0 |= LCCR0_LEN; 1052 1053 if (machine_is_shannon()) { 1054 GPDR |= SHANNON_GPIO_DISP_EN; 1055 GPSR |= SHANNON_GPIO_DISP_EN; 1056 } 1057 1058 DPRINTK("DBAR1 = 0x%08x\n", DBAR1); 1059 DPRINTK("DBAR2 = 0x%08x\n", DBAR2); 1060 DPRINTK("LCCR0 = 0x%08x\n", LCCR0); 1061 DPRINTK("LCCR1 = 0x%08x\n", LCCR1); 1062 DPRINTK("LCCR2 = 0x%08x\n", LCCR2); 1063 DPRINTK("LCCR3 = 0x%08x\n", LCCR3); 1064} 1065 1066static void sa1100fb_disable_controller(struct sa1100fb_info *fbi) 1067{ 1068 DECLARE_WAITQUEUE(wait, current); 1069 1070 DPRINTK("Disabling LCD controller\n"); 1071 1072 if (machine_is_shannon()) { 1073 GPCR |= SHANNON_GPIO_DISP_EN; 1074 } 1075 1076 set_current_state(TASK_UNINTERRUPTIBLE); 1077 add_wait_queue(&fbi->ctrlr_wait, &wait); 1078 1079 LCSR = 0xffffffff; /* Clear LCD Status Register */ 1080 LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ 1081 LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */ 1082 1083 schedule_timeout(20 * HZ / 1000); 1084 remove_wait_queue(&fbi->ctrlr_wait, &wait); 1085} 1086 1087/* 1088 * sa1100fb_handle_irq: Handle 'LCD DONE' interrupts. 1089 */ 1090static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) 1091{ 1092 struct sa1100fb_info *fbi = dev_id; 1093 unsigned int lcsr = LCSR; 1094 1095 if (lcsr & LCSR_LDD) { 1096 LCCR0 |= LCCR0_LDM; 1097 wake_up(&fbi->ctrlr_wait); 1098 } 1099 1100 LCSR = lcsr; 1101 return IRQ_HANDLED; 1102} 1103 1104/* 1105 * This function must be called from task context only, since it will 1106 * sleep when disabling the LCD controller, or if we get two contending 1107 * processes trying to alter state. 1108 */ 1109static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state) 1110{ 1111 u_int old_state; 1112 1113 down(&fbi->ctrlr_sem); 1114 1115 old_state = fbi->state; 1116 1117 /* 1118 * Hack around fbcon initialisation. 1119 */ 1120 if (old_state == C_STARTUP && state == C_REENABLE) 1121 state = C_ENABLE; 1122 1123 switch (state) { 1124 case C_DISABLE_CLKCHANGE: 1125 /* 1126 * Disable controller for clock change. If the 1127 * controller is already disabled, then do nothing. 1128 */ 1129 if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { 1130 fbi->state = state; 1131 sa1100fb_disable_controller(fbi); 1132 } 1133 break; 1134 1135 case C_DISABLE_PM: 1136 case C_DISABLE: 1137 /* 1138 * Disable controller 1139 */ 1140 if (old_state != C_DISABLE) { 1141 fbi->state = state; 1142 1143 __sa1100fb_backlight_power(fbi, 0); 1144 if (old_state != C_DISABLE_CLKCHANGE) 1145 sa1100fb_disable_controller(fbi); 1146 __sa1100fb_lcd_power(fbi, 0); 1147 } 1148 break; 1149 1150 case C_ENABLE_CLKCHANGE: 1151 /* 1152 * Enable the controller after clock change. Only 1153 * do this if we were disabled for the clock change. 1154 */ 1155 if (old_state == C_DISABLE_CLKCHANGE) { 1156 fbi->state = C_ENABLE; 1157 sa1100fb_enable_controller(fbi); 1158 } 1159 break; 1160 1161 case C_REENABLE: 1162 /* 1163 * Re-enable the controller only if it was already 1164 * enabled. This is so we reprogram the control 1165 * registers. 1166 */ 1167 if (old_state == C_ENABLE) { 1168 sa1100fb_disable_controller(fbi); 1169 sa1100fb_setup_gpio(fbi); 1170 sa1100fb_enable_controller(fbi); 1171 } 1172 break; 1173 1174 case C_ENABLE_PM: 1175 /* 1176 * Re-enable the controller after PM. This is not 1177 * perfect - think about the case where we were doing 1178 * a clock change, and we suspended half-way through. 1179 */ 1180 if (old_state != C_DISABLE_PM) 1181 break; 1182 /* fall through */ 1183 1184 case C_ENABLE: 1185 /* 1186 * Power up the LCD screen, enable controller, and 1187 * turn on the backlight. 1188 */ 1189 if (old_state != C_ENABLE) { 1190 fbi->state = C_ENABLE; 1191 sa1100fb_setup_gpio(fbi); 1192 __sa1100fb_lcd_power(fbi, 1); 1193 sa1100fb_enable_controller(fbi); 1194 __sa1100fb_backlight_power(fbi, 1); 1195 } 1196 break; 1197 } 1198 up(&fbi->ctrlr_sem); 1199} 1200 1201/* 1202 * Our LCD controller task (which is called when we blank or unblank) 1203 * via keventd. 1204 */ 1205static void sa1100fb_task(void *dummy) 1206{ 1207 struct sa1100fb_info *fbi = dummy; 1208 u_int state = xchg(&fbi->task_state, -1); 1209 1210 set_ctrlr_state(fbi, state); 1211} 1212 1213#ifdef CONFIG_CPU_FREQ 1214/* 1215 * Calculate the minimum DMA period over all displays that we own. 1216 * This, together with the SDRAM bandwidth defines the slowest CPU 1217 * frequency that can be selected. 1218 */ 1219static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi) 1220{ 1221#if 0 1222 unsigned int min_period = (unsigned int)-1; 1223 int i; 1224 1225 for (i = 0; i < MAX_NR_CONSOLES; i++) { 1226 struct display *disp = &fb_display[i]; 1227 unsigned int period; 1228 1229 /* 1230 * Do we own this display? 1231 */ 1232 if (disp->fb_info != &fbi->fb) 1233 continue; 1234 1235 /* 1236 * Ok, calculate its DMA period 1237 */ 1238 period = sa1100fb_display_dma_period(&disp->var); 1239 if (period < min_period) 1240 min_period = period; 1241 } 1242 1243 return min_period; 1244#else 1245 /* 1246 * FIXME: we need to verify _all_ consoles. 1247 */ 1248 return sa1100fb_display_dma_period(&fbi->fb.var); 1249#endif 1250} 1251 1252/* 1253 * CPU clock speed change handler. We need to adjust the LCD timing 1254 * parameters when the CPU clock is adjusted by the power management 1255 * subsystem. 1256 */ 1257static int 1258sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val, 1259 void *data) 1260{ 1261 struct sa1100fb_info *fbi = TO_INF(nb, freq_transition); 1262 struct cpufreq_freqs *f = data; 1263 u_int pcd; 1264 1265 switch (val) { 1266 case CPUFREQ_PRECHANGE: 1267 set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); 1268 break; 1269 1270 case CPUFREQ_POSTCHANGE: 1271 pcd = get_pcd(fbi->fb.var.pixclock, f->new); 1272 fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); 1273 set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); 1274 break; 1275 } 1276 return 0; 1277} 1278 1279static int 1280sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, 1281 void *data) 1282{ 1283 struct sa1100fb_info *fbi = TO_INF(nb, freq_policy); 1284 struct cpufreq_policy *policy = data; 1285 1286 switch (val) { 1287 case CPUFREQ_ADJUST: 1288 case CPUFREQ_INCOMPATIBLE: 1289 printk(KERN_DEBUG "min dma period: %d ps, " 1290 "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), 1291 policy->max); 1292 /* todo: fill in min/max values */ 1293 break; 1294 case CPUFREQ_NOTIFY: 1295 do {} while(0); 1296 /* todo: panic if min/max values aren't fulfilled 1297 * [can't really happen unless there's a bug in the 1298 * CPU policy verififcation process * 1299 */ 1300 break; 1301 } 1302 return 0; 1303} 1304#endif 1305 1306#ifdef CONFIG_PM 1307/* 1308 * Power management hooks. Note that we won't be called from IRQ context, 1309 * unlike the blank functions above, so we may sleep. 1310 */ 1311static int sa1100fb_suspend(struct platform_device *dev, pm_message_t state) 1312{ 1313 struct sa1100fb_info *fbi = platform_get_drvdata(dev); 1314 1315 set_ctrlr_state(fbi, C_DISABLE_PM); 1316 return 0; 1317} 1318 1319static int sa1100fb_resume(struct platform_device *dev) 1320{ 1321 struct sa1100fb_info *fbi = platform_get_drvdata(dev); 1322 1323 set_ctrlr_state(fbi, C_ENABLE_PM); 1324 return 0; 1325} 1326#else 1327#define sa1100fb_suspend NULL 1328#define sa1100fb_resume NULL 1329#endif 1330 1331/* 1332 * sa1100fb_map_video_memory(): 1333 * Allocates the DRAM memory for the frame buffer. This buffer is 1334 * remapped into a non-cached, non-buffered, memory region to 1335 * allow palette and pixel writes to occur without flushing the 1336 * cache. Once this area is remapped, all virtual memory 1337 * access to the video memory should occur at the new region. 1338 */ 1339static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi) 1340{ 1341 /* 1342 * We reserve one page for the palette, plus the size 1343 * of the framebuffer. 1344 */ 1345 fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); 1346 fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, 1347 &fbi->map_dma, GFP_KERNEL); 1348 1349 if (fbi->map_cpu) { 1350 fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; 1351 fbi->screen_dma = fbi->map_dma + PAGE_SIZE; 1352 /* 1353 * FIXME: this is actually the wrong thing to place in 1354 * smem_start. But fbdev suffers from the problem that 1355 * it needs an API which doesn't exist (in this case, 1356 * dma_writecombine_mmap) 1357 */ 1358 fbi->fb.fix.smem_start = fbi->screen_dma; 1359 } 1360 1361 return fbi->map_cpu ? 0 : -ENOMEM; 1362} 1363 1364/* Fake monspecs to fill in fbinfo structure */ 1365static struct fb_monspecs monspecs __initdata = { 1366 .hfmin = 30000, 1367 .hfmax = 70000, 1368 .vfmin = 50, 1369 .vfmax = 65, 1370}; 1371 1372 1373static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev) 1374{ 1375 struct sa1100fb_mach_info *inf; 1376 struct sa1100fb_info *fbi; 1377 1378 fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16, 1379 GFP_KERNEL); 1380 if (!fbi) 1381 return NULL; 1382 1383 memset(fbi, 0, sizeof(struct sa1100fb_info)); 1384 fbi->dev = dev; 1385 1386 strcpy(fbi->fb.fix.id, SA1100_NAME); 1387 1388 fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; 1389 fbi->fb.fix.type_aux = 0; 1390 fbi->fb.fix.xpanstep = 0; 1391 fbi->fb.fix.ypanstep = 0; 1392 fbi->fb.fix.ywrapstep = 0; 1393 fbi->fb.fix.accel = FB_ACCEL_NONE; 1394 1395 fbi->fb.var.nonstd = 0; 1396 fbi->fb.var.activate = FB_ACTIVATE_NOW; 1397 fbi->fb.var.height = -1; 1398 fbi->fb.var.width = -1; 1399 fbi->fb.var.accel_flags = 0; 1400 fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; 1401 1402 fbi->fb.fbops = &sa1100fb_ops; 1403 fbi->fb.flags = FBINFO_DEFAULT; 1404 fbi->fb.monspecs = monspecs; 1405 fbi->fb.pseudo_palette = (fbi + 1); 1406 1407 fbi->rgb[RGB_8] = &rgb_8; 1408 fbi->rgb[RGB_16] = &def_rgb_16; 1409 1410 inf = sa1100fb_get_machine_info(fbi); 1411 1412 /* 1413 * People just don't seem to get this. We don't support 1414 * anything but correct entries now, so panic if someone 1415 * does something stupid. 1416 */ 1417 if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) || 1418 inf->pixclock == 0) 1419 panic("sa1100fb error: invalid LCCR3 fields set or zero " 1420 "pixclock."); 1421 1422 fbi->max_xres = inf->xres; 1423 fbi->fb.var.xres = inf->xres; 1424 fbi->fb.var.xres_virtual = inf->xres; 1425 fbi->max_yres = inf->yres; 1426 fbi->fb.var.yres = inf->yres; 1427 fbi->fb.var.yres_virtual = inf->yres; 1428 fbi->max_bpp = inf->bpp; 1429 fbi->fb.var.bits_per_pixel = inf->bpp; 1430 fbi->fb.var.pixclock = inf->pixclock; 1431 fbi->fb.var.hsync_len = inf->hsync_len; 1432 fbi->fb.var.left_margin = inf->left_margin; 1433 fbi->fb.var.right_margin = inf->right_margin; 1434 fbi->fb.var.vsync_len = inf->vsync_len; 1435 fbi->fb.var.upper_margin = inf->upper_margin; 1436 fbi->fb.var.lower_margin = inf->lower_margin; 1437 fbi->fb.var.sync = inf->sync; 1438 fbi->fb.var.grayscale = inf->cmap_greyscale; 1439 fbi->cmap_inverse = inf->cmap_inverse; 1440 fbi->cmap_static = inf->cmap_static; 1441 fbi->lccr0 = inf->lccr0; 1442 fbi->lccr3 = inf->lccr3; 1443 fbi->state = C_STARTUP; 1444 fbi->task_state = (u_char)-1; 1445 fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * 1446 fbi->max_bpp / 8; 1447 1448 init_waitqueue_head(&fbi->ctrlr_wait); 1449 INIT_WORK(&fbi->task, sa1100fb_task, fbi); 1450 init_MUTEX(&fbi->ctrlr_sem); 1451 1452 return fbi; 1453} 1454 1455static int __init sa1100fb_probe(struct platform_device *pdev) 1456{ 1457 struct sa1100fb_info *fbi; 1458 int ret; 1459 1460 if (!request_mem_region(0xb0100000, 0x10000, "LCD")) 1461 return -EBUSY; 1462 1463 fbi = sa1100fb_init_fbinfo(&pdev->dev); 1464 ret = -ENOMEM; 1465 if (!fbi) 1466 goto failed; 1467 1468 /* Initialize video memory */ 1469 ret = sa1100fb_map_video_memory(fbi); 1470 if (ret) 1471 goto failed; 1472 1473 ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT, 1474 "LCD", fbi); 1475 if (ret) { 1476 printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); 1477 goto failed; 1478 } 1479 1480#ifdef ASSABET_PAL_VIDEO 1481 if (machine_is_assabet()) 1482 ASSABET_BCR_clear(ASSABET_BCR_LCD_ON); 1483#endif 1484 1485 /* 1486 * This makes sure that our colour bitfield 1487 * descriptors are correctly initialised. 1488 */ 1489 sa1100fb_check_var(&fbi->fb.var, &fbi->fb); 1490 1491 platform_set_drvdata(pdev, fbi); 1492 1493 ret = register_framebuffer(&fbi->fb); 1494 if (ret < 0) 1495 goto failed; 1496 1497#ifdef CONFIG_CPU_FREQ 1498 fbi->freq_transition.notifier_call = sa1100fb_freq_transition; 1499 fbi->freq_policy.notifier_call = sa1100fb_freq_policy; 1500 cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); 1501 cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER); 1502#endif 1503 1504 /* This driver cannot be unloaded at the moment */ 1505 return 0; 1506 1507failed: 1508 platform_set_drvdata(pdev, NULL); 1509 kfree(fbi); 1510 release_mem_region(0xb0100000, 0x10000); 1511 return ret; 1512} 1513 1514static struct platform_driver sa1100fb_driver = { 1515 .probe = sa1100fb_probe, 1516 .suspend = sa1100fb_suspend, 1517 .resume = sa1100fb_resume, 1518 .driver = { 1519 .name = "sa11x0-fb", 1520 }, 1521}; 1522 1523int __init sa1100fb_init(void) 1524{ 1525 if (fb_get_options("sa1100fb", NULL)) 1526 return -ENODEV; 1527 1528 return platform_driver_register(&sa1100fb_driver); 1529} 1530 1531int __init sa1100fb_setup(char *options) 1532{ 1533#if 0 1534 char *this_opt; 1535 1536 if (!options || !*options) 1537 return 0; 1538 1539 while ((this_opt = strsep(&options, ",")) != NULL) { 1540 1541 if (!strncmp(this_opt, "bpp:", 4)) 1542 current_par.max_bpp = 1543 simple_strtoul(this_opt + 4, NULL, 0); 1544 1545 if (!strncmp(this_opt, "lccr0:", 6)) 1546 lcd_shadow.lccr0 = 1547 simple_strtoul(this_opt + 6, NULL, 0); 1548 if (!strncmp(this_opt, "lccr1:", 6)) { 1549 lcd_shadow.lccr1 = 1550 simple_strtoul(this_opt + 6, NULL, 0); 1551 current_par.max_xres = 1552 (lcd_shadow.lccr1 & 0x3ff) + 16; 1553 } 1554 if (!strncmp(this_opt, "lccr2:", 6)) { 1555 lcd_shadow.lccr2 = 1556 simple_strtoul(this_opt + 6, NULL, 0); 1557 current_par.max_yres = 1558 (lcd_shadow. 1559 lccr0 & LCCR0_SDS) ? ((lcd_shadow. 1560 lccr2 & 0x3ff) + 1561 1) * 1562 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1); 1563 } 1564 if (!strncmp(this_opt, "lccr3:", 6)) 1565 lcd_shadow.lccr3 = 1566 simple_strtoul(this_opt + 6, NULL, 0); 1567 } 1568#endif 1569 return 0; 1570} 1571 1572module_init(sa1100fb_init); 1573MODULE_DESCRIPTION("StrongARM-1100/1110 framebuffer driver"); 1574MODULE_LICENSE("GPL");