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.37 1835 lines 48 kB view raw
1/* 2 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved. 3 * 4 * Freescale DIU Frame Buffer device driver 5 * 6 * Authors: Hongjun Chen <hong-jun.chen@freescale.com> 7 * Paul Widmer <paul.widmer@freescale.com> 8 * Srikanth Srinivasan <srikanth.srinivasan@freescale.com> 9 * York Sun <yorksun@freescale.com> 10 * 11 * Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of the GNU General Public License as published by the 15 * Free Software Foundation; either version 2 of the License, or (at your 16 * option) any later version. 17 * 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/slab.h> 25#include <linux/fb.h> 26#include <linux/init.h> 27#include <linux/dma-mapping.h> 28#include <linux/platform_device.h> 29#include <linux/interrupt.h> 30#include <linux/clk.h> 31#include <linux/uaccess.h> 32#include <linux/vmalloc.h> 33 34#include <linux/of_platform.h> 35 36#include <sysdev/fsl_soc.h> 37#include <linux/fsl-diu-fb.h> 38#include "edid.h" 39 40/* 41 * These parameters give default parameters 42 * for video output 1024x768, 43 * FIXME - change timing to proper amounts 44 * hsync 31.5kHz, vsync 60Hz 45 */ 46static struct fb_videomode __devinitdata fsl_diu_default_mode = { 47 .refresh = 60, 48 .xres = 1024, 49 .yres = 768, 50 .pixclock = 15385, 51 .left_margin = 160, 52 .right_margin = 24, 53 .upper_margin = 29, 54 .lower_margin = 3, 55 .hsync_len = 136, 56 .vsync_len = 6, 57 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 58 .vmode = FB_VMODE_NONINTERLACED 59}; 60 61static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { 62 { 63 .name = "1024x768-60", 64 .refresh = 60, 65 .xres = 1024, 66 .yres = 768, 67 .pixclock = 15385, 68 .left_margin = 160, 69 .right_margin = 24, 70 .upper_margin = 29, 71 .lower_margin = 3, 72 .hsync_len = 136, 73 .vsync_len = 6, 74 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 75 .vmode = FB_VMODE_NONINTERLACED 76 }, 77 { 78 .name = "1024x768-70", 79 .refresh = 70, 80 .xres = 1024, 81 .yres = 768, 82 .pixclock = 16886, 83 .left_margin = 3, 84 .right_margin = 3, 85 .upper_margin = 2, 86 .lower_margin = 2, 87 .hsync_len = 40, 88 .vsync_len = 18, 89 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 90 .vmode = FB_VMODE_NONINTERLACED 91 }, 92 { 93 .name = "1024x768-75", 94 .refresh = 75, 95 .xres = 1024, 96 .yres = 768, 97 .pixclock = 15009, 98 .left_margin = 3, 99 .right_margin = 3, 100 .upper_margin = 2, 101 .lower_margin = 2, 102 .hsync_len = 80, 103 .vsync_len = 32, 104 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 105 .vmode = FB_VMODE_NONINTERLACED 106 }, 107 { 108 .name = "1280x1024-60", 109 .refresh = 60, 110 .xres = 1280, 111 .yres = 1024, 112 .pixclock = 9375, 113 .left_margin = 38, 114 .right_margin = 128, 115 .upper_margin = 2, 116 .lower_margin = 7, 117 .hsync_len = 216, 118 .vsync_len = 37, 119 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 120 .vmode = FB_VMODE_NONINTERLACED 121 }, 122 { 123 .name = "1280x1024-70", 124 .refresh = 70, 125 .xres = 1280, 126 .yres = 1024, 127 .pixclock = 9380, 128 .left_margin = 6, 129 .right_margin = 6, 130 .upper_margin = 4, 131 .lower_margin = 4, 132 .hsync_len = 60, 133 .vsync_len = 94, 134 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 135 .vmode = FB_VMODE_NONINTERLACED 136 }, 137 { 138 .name = "1280x1024-75", 139 .refresh = 75, 140 .xres = 1280, 141 .yres = 1024, 142 .pixclock = 9380, 143 .left_margin = 6, 144 .right_margin = 6, 145 .upper_margin = 4, 146 .lower_margin = 4, 147 .hsync_len = 60, 148 .vsync_len = 15, 149 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 150 .vmode = FB_VMODE_NONINTERLACED 151 }, 152 { 153 .name = "320x240", /* for AOI only */ 154 .refresh = 60, 155 .xres = 320, 156 .yres = 240, 157 .pixclock = 15385, 158 .left_margin = 0, 159 .right_margin = 0, 160 .upper_margin = 0, 161 .lower_margin = 0, 162 .hsync_len = 0, 163 .vsync_len = 0, 164 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 165 .vmode = FB_VMODE_NONINTERLACED 166 }, 167 { 168 .name = "1280x480-60", 169 .refresh = 60, 170 .xres = 1280, 171 .yres = 480, 172 .pixclock = 18939, 173 .left_margin = 353, 174 .right_margin = 47, 175 .upper_margin = 39, 176 .lower_margin = 4, 177 .hsync_len = 8, 178 .vsync_len = 2, 179 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 180 .vmode = FB_VMODE_NONINTERLACED 181 }, 182}; 183 184static char *fb_mode = "1024x768-32@60"; 185static unsigned long default_bpp = 32; 186static int monitor_port; 187 188#if defined(CONFIG_NOT_COHERENT_CACHE) 189static u8 *coherence_data; 190static size_t coherence_data_size; 191static unsigned int d_cache_line_size; 192#endif 193 194static DEFINE_SPINLOCK(diu_lock); 195 196struct fsl_diu_data { 197 struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; 198 /*FSL_AOI_NUM has one dummy AOI */ 199 struct device_attribute dev_attr; 200 struct diu_ad *dummy_ad; 201 void *dummy_aoi_virt; 202 unsigned int irq; 203 int fb_enabled; 204 int monitor_port; 205}; 206 207struct mfb_info { 208 int index; 209 int type; 210 char *id; 211 int registered; 212 int blank; 213 unsigned long pseudo_palette[16]; 214 struct diu_ad *ad; 215 int cursor_reset; 216 unsigned char g_alpha; 217 unsigned int count; 218 int x_aoi_d; /* aoi display x offset to physical screen */ 219 int y_aoi_d; /* aoi display y offset to physical screen */ 220 struct fsl_diu_data *parent; 221 u8 *edid_data; 222}; 223 224 225static struct mfb_info mfb_template[] = { 226 { /* AOI 0 for plane 0 */ 227 .index = 0, 228 .type = MFB_TYPE_OUTPUT, 229 .id = "Panel0", 230 .registered = 0, 231 .count = 0, 232 .x_aoi_d = 0, 233 .y_aoi_d = 0, 234 }, 235 { /* AOI 0 for plane 1 */ 236 .index = 1, 237 .type = MFB_TYPE_OUTPUT, 238 .id = "Panel1 AOI0", 239 .registered = 0, 240 .g_alpha = 0xff, 241 .count = 0, 242 .x_aoi_d = 0, 243 .y_aoi_d = 0, 244 }, 245 { /* AOI 1 for plane 1 */ 246 .index = 2, 247 .type = MFB_TYPE_OUTPUT, 248 .id = "Panel1 AOI1", 249 .registered = 0, 250 .g_alpha = 0xff, 251 .count = 0, 252 .x_aoi_d = 0, 253 .y_aoi_d = 480, 254 }, 255 { /* AOI 0 for plane 2 */ 256 .index = 3, 257 .type = MFB_TYPE_OUTPUT, 258 .id = "Panel2 AOI0", 259 .registered = 0, 260 .g_alpha = 0xff, 261 .count = 0, 262 .x_aoi_d = 640, 263 .y_aoi_d = 0, 264 }, 265 { /* AOI 1 for plane 2 */ 266 .index = 4, 267 .type = MFB_TYPE_OUTPUT, 268 .id = "Panel2 AOI1", 269 .registered = 0, 270 .g_alpha = 0xff, 271 .count = 0, 272 .x_aoi_d = 640, 273 .y_aoi_d = 480, 274 }, 275}; 276 277static struct diu_hw dr = { 278 .mode = MFB_MODE1, 279 .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), 280}; 281 282static struct diu_pool pool; 283 284/** 285 * fsl_diu_alloc - allocate memory for the DIU 286 * @size: number of bytes to allocate 287 * @param: returned physical address of memory 288 * 289 * This function allocates a physically-contiguous block of memory. 290 */ 291static void *fsl_diu_alloc(size_t size, phys_addr_t *phys) 292{ 293 void *virt; 294 295 pr_debug("size=%zu\n", size); 296 297 virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO); 298 if (virt) { 299 *phys = virt_to_phys(virt); 300 pr_debug("virt=%p phys=%llx\n", virt, 301 (unsigned long long)*phys); 302 } 303 304 return virt; 305} 306 307/** 308 * fsl_diu_free - release DIU memory 309 * @virt: pointer returned by fsl_diu_alloc() 310 * @size: number of bytes allocated by fsl_diu_alloc() 311 * 312 * This function releases memory allocated by fsl_diu_alloc(). 313 */ 314static void fsl_diu_free(void *virt, size_t size) 315{ 316 pr_debug("virt=%p size=%zu\n", virt, size); 317 318 if (virt && size) 319 free_pages_exact(virt, size); 320} 321 322/* 323 * Workaround for failed writing desc register of planes. 324 * Needed with MPC5121 DIU rev 2.0 silicon. 325 */ 326void wr_reg_wa(u32 *reg, u32 val) 327{ 328 do { 329 out_be32(reg, val); 330 } while (in_be32(reg) != val); 331} 332 333static int fsl_diu_enable_panel(struct fb_info *info) 334{ 335 struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; 336 struct diu *hw = dr.diu_reg; 337 struct diu_ad *ad = mfbi->ad; 338 struct fsl_diu_data *machine_data = mfbi->parent; 339 int res = 0; 340 341 pr_debug("enable_panel index %d\n", mfbi->index); 342 if (mfbi->type != MFB_TYPE_OFF) { 343 switch (mfbi->index) { 344 case 0: /* plane 0 */ 345 if (hw->desc[0] != ad->paddr) 346 wr_reg_wa(&hw->desc[0], ad->paddr); 347 break; 348 case 1: /* plane 1 AOI 0 */ 349 cmfbi = machine_data->fsl_diu_info[2]->par; 350 if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ 351 if (cmfbi->count > 0) /* AOI1 open */ 352 ad->next_ad = 353 cpu_to_le32(cmfbi->ad->paddr); 354 else 355 ad->next_ad = 0; 356 wr_reg_wa(&hw->desc[1], ad->paddr); 357 } 358 break; 359 case 3: /* plane 2 AOI 0 */ 360 cmfbi = machine_data->fsl_diu_info[4]->par; 361 if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ 362 if (cmfbi->count > 0) /* AOI1 open */ 363 ad->next_ad = 364 cpu_to_le32(cmfbi->ad->paddr); 365 else 366 ad->next_ad = 0; 367 wr_reg_wa(&hw->desc[2], ad->paddr); 368 } 369 break; 370 case 2: /* plane 1 AOI 1 */ 371 pmfbi = machine_data->fsl_diu_info[1]->par; 372 ad->next_ad = 0; 373 if (hw->desc[1] == machine_data->dummy_ad->paddr) 374 wr_reg_wa(&hw->desc[1], ad->paddr); 375 else /* AOI0 open */ 376 pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); 377 break; 378 case 4: /* plane 2 AOI 1 */ 379 pmfbi = machine_data->fsl_diu_info[3]->par; 380 ad->next_ad = 0; 381 if (hw->desc[2] == machine_data->dummy_ad->paddr) 382 wr_reg_wa(&hw->desc[2], ad->paddr); 383 else /* AOI0 was open */ 384 pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); 385 break; 386 default: 387 res = -EINVAL; 388 break; 389 } 390 } else 391 res = -EINVAL; 392 return res; 393} 394 395static int fsl_diu_disable_panel(struct fb_info *info) 396{ 397 struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; 398 struct diu *hw = dr.diu_reg; 399 struct diu_ad *ad = mfbi->ad; 400 struct fsl_diu_data *machine_data = mfbi->parent; 401 int res = 0; 402 403 switch (mfbi->index) { 404 case 0: /* plane 0 */ 405 if (hw->desc[0] != machine_data->dummy_ad->paddr) 406 wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr); 407 break; 408 case 1: /* plane 1 AOI 0 */ 409 cmfbi = machine_data->fsl_diu_info[2]->par; 410 if (cmfbi->count > 0) /* AOI1 is open */ 411 wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); 412 /* move AOI1 to the first */ 413 else /* AOI1 was closed */ 414 wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); 415 /* close AOI 0 */ 416 break; 417 case 3: /* plane 2 AOI 0 */ 418 cmfbi = machine_data->fsl_diu_info[4]->par; 419 if (cmfbi->count > 0) /* AOI1 is open */ 420 wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); 421 /* move AOI1 to the first */ 422 else /* AOI1 was closed */ 423 wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); 424 /* close AOI 0 */ 425 break; 426 case 2: /* plane 1 AOI 1 */ 427 pmfbi = machine_data->fsl_diu_info[1]->par; 428 if (hw->desc[1] != ad->paddr) { 429 /* AOI1 is not the first in the chain */ 430 if (pmfbi->count > 0) 431 /* AOI0 is open, must be the first */ 432 pmfbi->ad->next_ad = 0; 433 } else /* AOI1 is the first in the chain */ 434 wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); 435 /* close AOI 1 */ 436 break; 437 case 4: /* plane 2 AOI 1 */ 438 pmfbi = machine_data->fsl_diu_info[3]->par; 439 if (hw->desc[2] != ad->paddr) { 440 /* AOI1 is not the first in the chain */ 441 if (pmfbi->count > 0) 442 /* AOI0 is open, must be the first */ 443 pmfbi->ad->next_ad = 0; 444 } else /* AOI1 is the first in the chain */ 445 wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); 446 /* close AOI 1 */ 447 break; 448 default: 449 res = -EINVAL; 450 break; 451 } 452 453 return res; 454} 455 456static void enable_lcdc(struct fb_info *info) 457{ 458 struct diu *hw = dr.diu_reg; 459 struct mfb_info *mfbi = info->par; 460 struct fsl_diu_data *machine_data = mfbi->parent; 461 462 if (!machine_data->fb_enabled) { 463 out_be32(&hw->diu_mode, dr.mode); 464 machine_data->fb_enabled++; 465 } 466} 467 468static void disable_lcdc(struct fb_info *info) 469{ 470 struct diu *hw = dr.diu_reg; 471 struct mfb_info *mfbi = info->par; 472 struct fsl_diu_data *machine_data = mfbi->parent; 473 474 if (machine_data->fb_enabled) { 475 out_be32(&hw->diu_mode, 0); 476 machine_data->fb_enabled = 0; 477 } 478} 479 480static void adjust_aoi_size_position(struct fb_var_screeninfo *var, 481 struct fb_info *info) 482{ 483 struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; 484 struct fsl_diu_data *machine_data = mfbi->parent; 485 int available_height, upper_aoi_bottom, index = mfbi->index; 486 int lower_aoi_is_open, upper_aoi_is_open; 487 __u32 base_plane_width, base_plane_height, upper_aoi_height; 488 489 base_plane_width = machine_data->fsl_diu_info[0]->var.xres; 490 base_plane_height = machine_data->fsl_diu_info[0]->var.yres; 491 492 if (mfbi->x_aoi_d < 0) 493 mfbi->x_aoi_d = 0; 494 if (mfbi->y_aoi_d < 0) 495 mfbi->y_aoi_d = 0; 496 switch (index) { 497 case 0: 498 if (mfbi->x_aoi_d != 0) 499 mfbi->x_aoi_d = 0; 500 if (mfbi->y_aoi_d != 0) 501 mfbi->y_aoi_d = 0; 502 break; 503 case 1: /* AOI 0 */ 504 case 3: 505 lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; 506 lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; 507 if (var->xres > base_plane_width) 508 var->xres = base_plane_width; 509 if ((mfbi->x_aoi_d + var->xres) > base_plane_width) 510 mfbi->x_aoi_d = base_plane_width - var->xres; 511 512 if (lower_aoi_is_open) 513 available_height = lower_aoi_mfbi->y_aoi_d; 514 else 515 available_height = base_plane_height; 516 if (var->yres > available_height) 517 var->yres = available_height; 518 if ((mfbi->y_aoi_d + var->yres) > available_height) 519 mfbi->y_aoi_d = available_height - var->yres; 520 break; 521 case 2: /* AOI 1 */ 522 case 4: 523 upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; 524 upper_aoi_height = 525 machine_data->fsl_diu_info[index-1]->var.yres; 526 upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; 527 upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; 528 if (var->xres > base_plane_width) 529 var->xres = base_plane_width; 530 if ((mfbi->x_aoi_d + var->xres) > base_plane_width) 531 mfbi->x_aoi_d = base_plane_width - var->xres; 532 if (mfbi->y_aoi_d < 0) 533 mfbi->y_aoi_d = 0; 534 if (upper_aoi_is_open) { 535 if (mfbi->y_aoi_d < upper_aoi_bottom) 536 mfbi->y_aoi_d = upper_aoi_bottom; 537 available_height = base_plane_height 538 - upper_aoi_bottom; 539 } else 540 available_height = base_plane_height; 541 if (var->yres > available_height) 542 var->yres = available_height; 543 if ((mfbi->y_aoi_d + var->yres) > base_plane_height) 544 mfbi->y_aoi_d = base_plane_height - var->yres; 545 break; 546 } 547} 548/* 549 * Checks to see if the hardware supports the state requested by var passed 550 * in. This function does not alter the hardware state! If the var passed in 551 * is slightly off by what the hardware can support then we alter the var 552 * PASSED in to what we can do. If the hardware doesn't support mode change 553 * a -EINVAL will be returned by the upper layers. 554 */ 555static int fsl_diu_check_var(struct fb_var_screeninfo *var, 556 struct fb_info *info) 557{ 558 unsigned long htotal, vtotal; 559 560 pr_debug("check_var xres: %d\n", var->xres); 561 pr_debug("check_var yres: %d\n", var->yres); 562 563 if (var->xres_virtual < var->xres) 564 var->xres_virtual = var->xres; 565 if (var->yres_virtual < var->yres) 566 var->yres_virtual = var->yres; 567 568 if (var->xoffset < 0) 569 var->xoffset = 0; 570 571 if (var->yoffset < 0) 572 var->yoffset = 0; 573 574 if (var->xoffset + info->var.xres > info->var.xres_virtual) 575 var->xoffset = info->var.xres_virtual - info->var.xres; 576 577 if (var->yoffset + info->var.yres > info->var.yres_virtual) 578 var->yoffset = info->var.yres_virtual - info->var.yres; 579 580 if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && 581 (var->bits_per_pixel != 16)) 582 var->bits_per_pixel = default_bpp; 583 584 switch (var->bits_per_pixel) { 585 case 16: 586 var->red.length = 5; 587 var->red.offset = 11; 588 var->red.msb_right = 0; 589 590 var->green.length = 6; 591 var->green.offset = 5; 592 var->green.msb_right = 0; 593 594 var->blue.length = 5; 595 var->blue.offset = 0; 596 var->blue.msb_right = 0; 597 598 var->transp.length = 0; 599 var->transp.offset = 0; 600 var->transp.msb_right = 0; 601 break; 602 case 24: 603 var->red.length = 8; 604 var->red.offset = 0; 605 var->red.msb_right = 0; 606 607 var->green.length = 8; 608 var->green.offset = 8; 609 var->green.msb_right = 0; 610 611 var->blue.length = 8; 612 var->blue.offset = 16; 613 var->blue.msb_right = 0; 614 615 var->transp.length = 0; 616 var->transp.offset = 0; 617 var->transp.msb_right = 0; 618 break; 619 case 32: 620 var->red.length = 8; 621 var->red.offset = 16; 622 var->red.msb_right = 0; 623 624 var->green.length = 8; 625 var->green.offset = 8; 626 var->green.msb_right = 0; 627 628 var->blue.length = 8; 629 var->blue.offset = 0; 630 var->blue.msb_right = 0; 631 632 var->transp.length = 8; 633 var->transp.offset = 24; 634 var->transp.msb_right = 0; 635 636 break; 637 } 638 /* If the pixclock is below the minimum spec'd value then set to 639 * refresh rate for 60Hz since this is supported by most monitors. 640 * Refer to Documentation/fb/ for calculations. 641 */ 642 if ((var->pixclock < MIN_PIX_CLK) || (var->pixclock > MAX_PIX_CLK)) { 643 htotal = var->xres + var->right_margin + var->hsync_len + 644 var->left_margin; 645 vtotal = var->yres + var->lower_margin + var->vsync_len + 646 var->upper_margin; 647 var->pixclock = (vtotal * htotal * 6UL) / 100UL; 648 var->pixclock = KHZ2PICOS(var->pixclock); 649 pr_debug("pixclock set for 60Hz refresh = %u ps\n", 650 var->pixclock); 651 } 652 653 var->height = -1; 654 var->width = -1; 655 var->grayscale = 0; 656 657 /* Copy nonstd field to/from sync for fbset usage */ 658 var->sync |= var->nonstd; 659 var->nonstd |= var->sync; 660 661 adjust_aoi_size_position(var, info); 662 return 0; 663} 664 665static void set_fix(struct fb_info *info) 666{ 667 struct fb_fix_screeninfo *fix = &info->fix; 668 struct fb_var_screeninfo *var = &info->var; 669 struct mfb_info *mfbi = info->par; 670 671 strncpy(fix->id, mfbi->id, strlen(mfbi->id)); 672 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; 673 fix->type = FB_TYPE_PACKED_PIXELS; 674 fix->accel = FB_ACCEL_NONE; 675 fix->visual = FB_VISUAL_TRUECOLOR; 676 fix->xpanstep = 1; 677 fix->ypanstep = 1; 678} 679 680static void update_lcdc(struct fb_info *info) 681{ 682 struct fb_var_screeninfo *var = &info->var; 683 struct mfb_info *mfbi = info->par; 684 struct fsl_diu_data *machine_data = mfbi->parent; 685 struct diu *hw; 686 int i, j; 687 char __iomem *cursor_base, *gamma_table_base; 688 689 u32 temp; 690 691 hw = dr.diu_reg; 692 693 if (mfbi->type == MFB_TYPE_OFF) { 694 fsl_diu_disable_panel(info); 695 return; 696 } 697 698 diu_ops.set_monitor_port(machine_data->monitor_port); 699 gamma_table_base = pool.gamma.vaddr; 700 cursor_base = pool.cursor.vaddr; 701 /* Prep for DIU init - gamma table, cursor table */ 702 703 for (i = 0; i <= 2; i++) 704 for (j = 0; j <= 255; j++) 705 *gamma_table_base++ = j; 706 707 diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr); 708 709 pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw); 710 disable_lcdc(info); 711 712 /* Program DIU registers */ 713 714 out_be32(&hw->gamma, pool.gamma.paddr); 715 out_be32(&hw->cursor, pool.cursor.paddr); 716 717 out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ 718 out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ 719 out_be32(&hw->disp_size, (var->yres << 16 | var->xres)); 720 /* DISP SIZE */ 721 pr_debug("DIU xres: %d\n", var->xres); 722 pr_debug("DIU yres: %d\n", var->yres); 723 724 out_be32(&hw->wb_size, 0); /* WB SIZE */ 725 out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ 726 727 /* Horizontal and vertical configuration register */ 728 temp = var->left_margin << 22 | /* BP_H */ 729 var->hsync_len << 11 | /* PW_H */ 730 var->right_margin; /* FP_H */ 731 732 out_be32(&hw->hsyn_para, temp); 733 734 temp = var->upper_margin << 22 | /* BP_V */ 735 var->vsync_len << 11 | /* PW_V */ 736 var->lower_margin; /* FP_V */ 737 738 out_be32(&hw->vsyn_para, temp); 739 740 pr_debug("DIU right_margin - %d\n", var->right_margin); 741 pr_debug("DIU left_margin - %d\n", var->left_margin); 742 pr_debug("DIU hsync_len - %d\n", var->hsync_len); 743 pr_debug("DIU upper_margin - %d\n", var->upper_margin); 744 pr_debug("DIU lower_margin - %d\n", var->lower_margin); 745 pr_debug("DIU vsync_len - %d\n", var->vsync_len); 746 pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para); 747 pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para); 748 749 diu_ops.set_pixel_clock(var->pixclock); 750 751 out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ 752 out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ 753 out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ 754 out_be32(&hw->plut, 0x01F5F666); 755 756 /* Enable the DIU */ 757 enable_lcdc(info); 758} 759 760static int map_video_memory(struct fb_info *info) 761{ 762 phys_addr_t phys; 763 u32 smem_len = info->fix.line_length * info->var.yres_virtual; 764 765 pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); 766 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 767 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 768 pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len); 769 770 info->screen_base = fsl_diu_alloc(smem_len, &phys); 771 if (info->screen_base == NULL) { 772 printk(KERN_ERR "Unable to allocate fb memory\n"); 773 return -ENOMEM; 774 } 775 mutex_lock(&info->mm_lock); 776 info->fix.smem_start = (unsigned long) phys; 777 info->fix.smem_len = smem_len; 778 mutex_unlock(&info->mm_lock); 779 info->screen_size = info->fix.smem_len; 780 781 pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", 782 info->fix.smem_start, info->fix.smem_len); 783 pr_debug("screen base %p\n", info->screen_base); 784 785 return 0; 786} 787 788static void unmap_video_memory(struct fb_info *info) 789{ 790 fsl_diu_free(info->screen_base, info->fix.smem_len); 791 mutex_lock(&info->mm_lock); 792 info->screen_base = NULL; 793 info->fix.smem_start = 0; 794 info->fix.smem_len = 0; 795 mutex_unlock(&info->mm_lock); 796} 797 798/* 799 * Using the fb_var_screeninfo in fb_info we set the aoi of this 800 * particular framebuffer. It is a light version of fsl_diu_set_par. 801 */ 802static int fsl_diu_set_aoi(struct fb_info *info) 803{ 804 struct fb_var_screeninfo *var = &info->var; 805 struct mfb_info *mfbi = info->par; 806 struct diu_ad *ad = mfbi->ad; 807 808 /* AOI should not be greater than display size */ 809 ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); 810 ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); 811 return 0; 812} 813 814/* 815 * Using the fb_var_screeninfo in fb_info we set the resolution of this 816 * particular framebuffer. This function alters the fb_fix_screeninfo stored 817 * in fb_info. It does not alter var in fb_info since we are using that 818 * data. This means we depend on the data in var inside fb_info to be 819 * supported by the hardware. fsl_diu_check_var is always called before 820 * fsl_diu_set_par to ensure this. 821 */ 822static int fsl_diu_set_par(struct fb_info *info) 823{ 824 unsigned long len; 825 struct fb_var_screeninfo *var = &info->var; 826 struct mfb_info *mfbi = info->par; 827 struct fsl_diu_data *machine_data = mfbi->parent; 828 struct diu_ad *ad = mfbi->ad; 829 struct diu *hw; 830 831 hw = dr.diu_reg; 832 833 set_fix(info); 834 mfbi->cursor_reset = 1; 835 836 len = info->var.yres_virtual * info->fix.line_length; 837 /* Alloc & dealloc each time resolution/bpp change */ 838 if (len != info->fix.smem_len) { 839 if (info->fix.smem_start) 840 unmap_video_memory(info); 841 pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len); 842 843 /* Memory allocation for framebuffer */ 844 if (map_video_memory(info)) { 845 printk(KERN_ERR "Unable to allocate fb memory 1\n"); 846 return -ENOMEM; 847 } 848 } 849 850 ad->pix_fmt = 851 diu_ops.get_pixel_format(var->bits_per_pixel, 852 machine_data->monitor_port); 853 ad->addr = cpu_to_le32(info->fix.smem_start); 854 ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | 855 var->xres_virtual) | mfbi->g_alpha; 856 /* AOI should not be greater than display size */ 857 ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); 858 ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); 859 ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); 860 861 /* Disable chroma keying function */ 862 ad->ckmax_r = 0; 863 ad->ckmax_g = 0; 864 ad->ckmax_b = 0; 865 866 ad->ckmin_r = 255; 867 ad->ckmin_g = 255; 868 ad->ckmin_b = 255; 869 870 if (mfbi->index == 0) 871 update_lcdc(info); 872 return 0; 873} 874 875static inline __u32 CNVT_TOHW(__u32 val, __u32 width) 876{ 877 return ((val<<width) + 0x7FFF - val)>>16; 878} 879 880/* 881 * Set a single color register. The values supplied have a 16 bit magnitude 882 * which needs to be scaled in this function for the hardware. Things to take 883 * into consideration are how many color registers, if any, are supported with 884 * the current color visual. With truecolor mode no color palettes are 885 * supported. Here a psuedo palette is created which we store the value in 886 * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited 887 * color palette. 888 */ 889static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green, 890 unsigned blue, unsigned transp, struct fb_info *info) 891{ 892 int ret = 1; 893 894 /* 895 * If greyscale is true, then we convert the RGB value 896 * to greyscale no matter what visual we are using. 897 */ 898 if (info->var.grayscale) 899 red = green = blue = (19595 * red + 38470 * green + 900 7471 * blue) >> 16; 901 switch (info->fix.visual) { 902 case FB_VISUAL_TRUECOLOR: 903 /* 904 * 16-bit True Colour. We encode the RGB value 905 * according to the RGB bitfield information. 906 */ 907 if (regno < 16) { 908 u32 *pal = info->pseudo_palette; 909 u32 v; 910 911 red = CNVT_TOHW(red, info->var.red.length); 912 green = CNVT_TOHW(green, info->var.green.length); 913 blue = CNVT_TOHW(blue, info->var.blue.length); 914 transp = CNVT_TOHW(transp, info->var.transp.length); 915 916 v = (red << info->var.red.offset) | 917 (green << info->var.green.offset) | 918 (blue << info->var.blue.offset) | 919 (transp << info->var.transp.offset); 920 921 pal[regno] = v; 922 ret = 0; 923 } 924 break; 925 case FB_VISUAL_STATIC_PSEUDOCOLOR: 926 case FB_VISUAL_PSEUDOCOLOR: 927 break; 928 } 929 930 return ret; 931} 932 933/* 934 * Pan (or wrap, depending on the `vmode' field) the display using the 935 * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values 936 * don't fit, return -EINVAL. 937 */ 938static int fsl_diu_pan_display(struct fb_var_screeninfo *var, 939 struct fb_info *info) 940{ 941 if ((info->var.xoffset == var->xoffset) && 942 (info->var.yoffset == var->yoffset)) 943 return 0; /* No change, do nothing */ 944 945 if (var->xoffset < 0 || var->yoffset < 0 946 || var->xoffset + info->var.xres > info->var.xres_virtual 947 || var->yoffset + info->var.yres > info->var.yres_virtual) 948 return -EINVAL; 949 950 info->var.xoffset = var->xoffset; 951 info->var.yoffset = var->yoffset; 952 953 if (var->vmode & FB_VMODE_YWRAP) 954 info->var.vmode |= FB_VMODE_YWRAP; 955 else 956 info->var.vmode &= ~FB_VMODE_YWRAP; 957 958 fsl_diu_set_aoi(info); 959 960 return 0; 961} 962 963/* 964 * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking 965 * succeeded, != 0 if un-/blanking failed. 966 * blank_mode == 2: suspend vsync 967 * blank_mode == 3: suspend hsync 968 * blank_mode == 4: powerdown 969 */ 970static int fsl_diu_blank(int blank_mode, struct fb_info *info) 971{ 972 struct mfb_info *mfbi = info->par; 973 974 mfbi->blank = blank_mode; 975 976 switch (blank_mode) { 977 case FB_BLANK_VSYNC_SUSPEND: 978 case FB_BLANK_HSYNC_SUSPEND: 979 /* FIXME: fixes to enable_panel and enable lcdc needed */ 980 case FB_BLANK_NORMAL: 981 /* fsl_diu_disable_panel(info);*/ 982 break; 983 case FB_BLANK_POWERDOWN: 984 /* disable_lcdc(info); */ 985 break; 986 case FB_BLANK_UNBLANK: 987 /* fsl_diu_enable_panel(info);*/ 988 break; 989 } 990 991 return 0; 992} 993 994static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, 995 unsigned long arg) 996{ 997 struct mfb_info *mfbi = info->par; 998 struct diu_ad *ad = mfbi->ad; 999 struct mfb_chroma_key ck; 1000 unsigned char global_alpha; 1001 struct aoi_display_offset aoi_d; 1002 __u32 pix_fmt; 1003 void __user *buf = (void __user *)arg; 1004 1005 if (!arg) 1006 return -EINVAL; 1007 switch (cmd) { 1008 case MFB_SET_PIXFMT: 1009 if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) 1010 return -EFAULT; 1011 ad->pix_fmt = pix_fmt; 1012 pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); 1013 break; 1014 case MFB_GET_PIXFMT: 1015 pix_fmt = ad->pix_fmt; 1016 if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) 1017 return -EFAULT; 1018 pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); 1019 break; 1020 case MFB_SET_AOID: 1021 if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) 1022 return -EFAULT; 1023 mfbi->x_aoi_d = aoi_d.x_aoi_d; 1024 mfbi->y_aoi_d = aoi_d.y_aoi_d; 1025 pr_debug("set AOI display offset of index %d to (%d,%d)\n", 1026 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1027 fsl_diu_check_var(&info->var, info); 1028 fsl_diu_set_aoi(info); 1029 break; 1030 case MFB_GET_AOID: 1031 aoi_d.x_aoi_d = mfbi->x_aoi_d; 1032 aoi_d.y_aoi_d = mfbi->y_aoi_d; 1033 if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) 1034 return -EFAULT; 1035 pr_debug("get AOI display offset of index %d (%d,%d)\n", 1036 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1037 break; 1038 case MFB_GET_ALPHA: 1039 global_alpha = mfbi->g_alpha; 1040 if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) 1041 return -EFAULT; 1042 pr_debug("get global alpha of index %d\n", mfbi->index); 1043 break; 1044 case MFB_SET_ALPHA: 1045 /* set panel information */ 1046 if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) 1047 return -EFAULT; 1048 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | 1049 (global_alpha & 0xff); 1050 mfbi->g_alpha = global_alpha; 1051 pr_debug("set global alpha for index %d\n", mfbi->index); 1052 break; 1053 case MFB_SET_CHROMA_KEY: 1054 /* set panel winformation */ 1055 if (copy_from_user(&ck, buf, sizeof(ck))) 1056 return -EFAULT; 1057 1058 if (ck.enable && 1059 (ck.red_max < ck.red_min || 1060 ck.green_max < ck.green_min || 1061 ck.blue_max < ck.blue_min)) 1062 return -EINVAL; 1063 1064 if (!ck.enable) { 1065 ad->ckmax_r = 0; 1066 ad->ckmax_g = 0; 1067 ad->ckmax_b = 0; 1068 ad->ckmin_r = 255; 1069 ad->ckmin_g = 255; 1070 ad->ckmin_b = 255; 1071 } else { 1072 ad->ckmax_r = ck.red_max; 1073 ad->ckmax_g = ck.green_max; 1074 ad->ckmax_b = ck.blue_max; 1075 ad->ckmin_r = ck.red_min; 1076 ad->ckmin_g = ck.green_min; 1077 ad->ckmin_b = ck.blue_min; 1078 } 1079 pr_debug("set chroma key\n"); 1080 break; 1081 case FBIOGET_GWINFO: 1082 if (mfbi->type == MFB_TYPE_OFF) 1083 return -ENODEV; 1084 /* get graphic window information */ 1085 if (copy_to_user(buf, ad, sizeof(*ad))) 1086 return -EFAULT; 1087 break; 1088 case FBIOGET_HWCINFO: 1089 pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); 1090 break; 1091 case FBIOPUT_MODEINFO: 1092 pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); 1093 break; 1094 case FBIOGET_DISPINFO: 1095 pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); 1096 break; 1097 1098 default: 1099 printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); 1100 return -ENOIOCTLCMD; 1101 } 1102 1103 return 0; 1104} 1105 1106/* turn on fb if count == 1 1107 */ 1108static int fsl_diu_open(struct fb_info *info, int user) 1109{ 1110 struct mfb_info *mfbi = info->par; 1111 int res = 0; 1112 1113 /* free boot splash memory on first /dev/fb0 open */ 1114 if (!mfbi->index && diu_ops.release_bootmem) 1115 diu_ops.release_bootmem(); 1116 1117 spin_lock(&diu_lock); 1118 mfbi->count++; 1119 if (mfbi->count == 1) { 1120 pr_debug("open plane index %d\n", mfbi->index); 1121 fsl_diu_check_var(&info->var, info); 1122 res = fsl_diu_set_par(info); 1123 if (res < 0) 1124 mfbi->count--; 1125 else { 1126 res = fsl_diu_enable_panel(info); 1127 if (res < 0) 1128 mfbi->count--; 1129 } 1130 } 1131 1132 spin_unlock(&diu_lock); 1133 return res; 1134} 1135 1136/* turn off fb if count == 0 1137 */ 1138static int fsl_diu_release(struct fb_info *info, int user) 1139{ 1140 struct mfb_info *mfbi = info->par; 1141 int res = 0; 1142 1143 spin_lock(&diu_lock); 1144 mfbi->count--; 1145 if (mfbi->count == 0) { 1146 pr_debug("release plane index %d\n", mfbi->index); 1147 res = fsl_diu_disable_panel(info); 1148 if (res < 0) 1149 mfbi->count++; 1150 } 1151 spin_unlock(&diu_lock); 1152 return res; 1153} 1154 1155static struct fb_ops fsl_diu_ops = { 1156 .owner = THIS_MODULE, 1157 .fb_check_var = fsl_diu_check_var, 1158 .fb_set_par = fsl_diu_set_par, 1159 .fb_setcolreg = fsl_diu_setcolreg, 1160 .fb_blank = fsl_diu_blank, 1161 .fb_pan_display = fsl_diu_pan_display, 1162 .fb_fillrect = cfb_fillrect, 1163 .fb_copyarea = cfb_copyarea, 1164 .fb_imageblit = cfb_imageblit, 1165 .fb_ioctl = fsl_diu_ioctl, 1166 .fb_open = fsl_diu_open, 1167 .fb_release = fsl_diu_release, 1168}; 1169 1170static int init_fbinfo(struct fb_info *info) 1171{ 1172 struct mfb_info *mfbi = info->par; 1173 1174 info->device = NULL; 1175 info->var.activate = FB_ACTIVATE_NOW; 1176 info->fbops = &fsl_diu_ops; 1177 info->flags = FBINFO_FLAG_DEFAULT; 1178 info->pseudo_palette = &mfbi->pseudo_palette; 1179 1180 /* Allocate colormap */ 1181 fb_alloc_cmap(&info->cmap, 16, 0); 1182 return 0; 1183} 1184 1185static int __devinit install_fb(struct fb_info *info) 1186{ 1187 int rc; 1188 struct mfb_info *mfbi = info->par; 1189 const char *aoi_mode, *init_aoi_mode = "320x240"; 1190 struct fb_videomode *db = fsl_diu_mode_db; 1191 unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); 1192 int has_default_mode = 1; 1193 1194 if (init_fbinfo(info)) 1195 return -EINVAL; 1196 1197 if (mfbi->index == 0) { /* plane 0 */ 1198 if (mfbi->edid_data) { 1199 /* Now build modedb from EDID */ 1200 fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs); 1201 fb_videomode_to_modelist(info->monspecs.modedb, 1202 info->monspecs.modedb_len, 1203 &info->modelist); 1204 db = info->monspecs.modedb; 1205 dbsize = info->monspecs.modedb_len; 1206 } 1207 aoi_mode = fb_mode; 1208 } else { 1209 aoi_mode = init_aoi_mode; 1210 } 1211 pr_debug("mode used = %s\n", aoi_mode); 1212 rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, 1213 &fsl_diu_default_mode, default_bpp); 1214 switch (rc) { 1215 case 1: 1216 pr_debug("using mode specified in @mode\n"); 1217 break; 1218 case 2: 1219 pr_debug("using mode specified in @mode " 1220 "with ignored refresh rate\n"); 1221 break; 1222 case 3: 1223 pr_debug("using mode default mode\n"); 1224 break; 1225 case 4: 1226 pr_debug("using mode from list\n"); 1227 break; 1228 default: 1229 pr_debug("rc = %d\n", rc); 1230 pr_debug("failed to find mode\n"); 1231 /* 1232 * For plane 0 we continue and look into 1233 * driver's internal modedb. 1234 */ 1235 if (mfbi->index == 0 && mfbi->edid_data) 1236 has_default_mode = 0; 1237 else 1238 return -EINVAL; 1239 break; 1240 } 1241 1242 if (!has_default_mode) { 1243 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, 1244 ARRAY_SIZE(fsl_diu_mode_db), 1245 &fsl_diu_default_mode, 1246 default_bpp); 1247 if (rc > 0 && rc < 5) 1248 has_default_mode = 1; 1249 } 1250 1251 /* Still not found, use preferred mode from database if any */ 1252 if (!has_default_mode && info->monspecs.modedb) { 1253 struct fb_monspecs *specs = &info->monspecs; 1254 struct fb_videomode *modedb = &specs->modedb[0]; 1255 1256 /* 1257 * Get preferred timing. If not found, 1258 * first mode in database will be used. 1259 */ 1260 if (specs->misc & FB_MISC_1ST_DETAIL) { 1261 int i; 1262 1263 for (i = 0; i < specs->modedb_len; i++) { 1264 if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { 1265 modedb = &specs->modedb[i]; 1266 break; 1267 } 1268 } 1269 } 1270 1271 info->var.bits_per_pixel = default_bpp; 1272 fb_videomode_to_var(&info->var, modedb); 1273 } 1274 1275 pr_debug("xres_virtual %d\n", info->var.xres_virtual); 1276 pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); 1277 1278 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 1279 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 1280 1281 if (mfbi->type == MFB_TYPE_OFF) 1282 mfbi->blank = FB_BLANK_NORMAL; 1283 else 1284 mfbi->blank = FB_BLANK_UNBLANK; 1285 1286 if (fsl_diu_check_var(&info->var, info)) { 1287 printk(KERN_ERR "fb_check_var failed"); 1288 fb_dealloc_cmap(&info->cmap); 1289 return -EINVAL; 1290 } 1291 1292 if (register_framebuffer(info) < 0) { 1293 printk(KERN_ERR "register_framebuffer failed"); 1294 unmap_video_memory(info); 1295 fb_dealloc_cmap(&info->cmap); 1296 return -EINVAL; 1297 } 1298 1299 mfbi->registered = 1; 1300 printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", 1301 info->node, info->fix.id); 1302 1303 return 0; 1304} 1305 1306static void uninstall_fb(struct fb_info *info) 1307{ 1308 struct mfb_info *mfbi = info->par; 1309 1310 if (!mfbi->registered) 1311 return; 1312 1313 if (mfbi->index == 0) 1314 kfree(mfbi->edid_data); 1315 1316 unregister_framebuffer(info); 1317 unmap_video_memory(info); 1318 if (&info->cmap) 1319 fb_dealloc_cmap(&info->cmap); 1320 1321 mfbi->registered = 0; 1322} 1323 1324static irqreturn_t fsl_diu_isr(int irq, void *dev_id) 1325{ 1326 struct diu *hw = dr.diu_reg; 1327 unsigned int status = in_be32(&hw->int_status); 1328 1329 if (status) { 1330 /* This is the workaround for underrun */ 1331 if (status & INT_UNDRUN) { 1332 out_be32(&hw->diu_mode, 0); 1333 pr_debug("Err: DIU occurs underrun!\n"); 1334 udelay(1); 1335 out_be32(&hw->diu_mode, 1); 1336 } 1337#if defined(CONFIG_NOT_COHERENT_CACHE) 1338 else if (status & INT_VSYNC) { 1339 unsigned int i; 1340 for (i = 0; i < coherence_data_size; 1341 i += d_cache_line_size) 1342 __asm__ __volatile__ ( 1343 "dcbz 0, %[input]" 1344 ::[input]"r"(&coherence_data[i])); 1345 } 1346#endif 1347 return IRQ_HANDLED; 1348 } 1349 return IRQ_NONE; 1350} 1351 1352static int request_irq_local(int irq) 1353{ 1354 unsigned long status, ints; 1355 struct diu *hw; 1356 int ret; 1357 1358 hw = dr.diu_reg; 1359 1360 /* Read to clear the status */ 1361 status = in_be32(&hw->int_status); 1362 1363 ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL); 1364 if (ret) 1365 pr_info("Request diu IRQ failed.\n"); 1366 else { 1367 ints = INT_PARERR | INT_LS_BF_VS; 1368#if !defined(CONFIG_NOT_COHERENT_CACHE) 1369 ints |= INT_VSYNC; 1370#endif 1371 if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) 1372 ints |= INT_VSYNC_WB; 1373 1374 /* Read to clear the status */ 1375 status = in_be32(&hw->int_status); 1376 out_be32(&hw->int_mask, ints); 1377 } 1378 return ret; 1379} 1380 1381static void free_irq_local(int irq) 1382{ 1383 struct diu *hw = dr.diu_reg; 1384 1385 /* Disable all LCDC interrupt */ 1386 out_be32(&hw->int_mask, 0x1f); 1387 1388 free_irq(irq, NULL); 1389} 1390 1391#ifdef CONFIG_PM 1392/* 1393 * Power management hooks. Note that we won't be called from IRQ context, 1394 * unlike the blank functions above, so we may sleep. 1395 */ 1396static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) 1397{ 1398 struct fsl_diu_data *machine_data; 1399 1400 machine_data = dev_get_drvdata(&ofdev->dev); 1401 disable_lcdc(machine_data->fsl_diu_info[0]); 1402 1403 return 0; 1404} 1405 1406static int fsl_diu_resume(struct platform_device *ofdev) 1407{ 1408 struct fsl_diu_data *machine_data; 1409 1410 machine_data = dev_get_drvdata(&ofdev->dev); 1411 enable_lcdc(machine_data->fsl_diu_info[0]); 1412 1413 return 0; 1414} 1415 1416#else 1417#define fsl_diu_suspend NULL 1418#define fsl_diu_resume NULL 1419#endif /* CONFIG_PM */ 1420 1421/* Align to 64-bit(8-byte), 32-byte, etc. */ 1422static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, 1423 u32 bytes_align) 1424{ 1425 u32 offset, ssize; 1426 u32 mask; 1427 dma_addr_t paddr = 0; 1428 1429 ssize = size + bytes_align; 1430 buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA | 1431 __GFP_ZERO); 1432 if (!buf->vaddr) 1433 return -ENOMEM; 1434 1435 buf->paddr = (__u32) paddr; 1436 1437 mask = bytes_align - 1; 1438 offset = (u32)buf->paddr & mask; 1439 if (offset) { 1440 buf->offset = bytes_align - offset; 1441 buf->paddr = (u32)buf->paddr + offset; 1442 } else 1443 buf->offset = 0; 1444 return 0; 1445} 1446 1447static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, 1448 u32 bytes_align) 1449{ 1450 dma_free_coherent(dev, size + bytes_align, 1451 buf->vaddr, (buf->paddr - buf->offset)); 1452 return; 1453} 1454 1455static ssize_t store_monitor(struct device *device, 1456 struct device_attribute *attr, const char *buf, size_t count) 1457{ 1458 int old_monitor_port; 1459 unsigned long val; 1460 struct fsl_diu_data *machine_data = 1461 container_of(attr, struct fsl_diu_data, dev_attr); 1462 1463 if (strict_strtoul(buf, 10, &val)) 1464 return 0; 1465 1466 old_monitor_port = machine_data->monitor_port; 1467 machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); 1468 1469 if (old_monitor_port != machine_data->monitor_port) { 1470 /* All AOIs need adjust pixel format 1471 * fsl_diu_set_par only change the pixsel format here 1472 * unlikely to fail. */ 1473 fsl_diu_set_par(machine_data->fsl_diu_info[0]); 1474 fsl_diu_set_par(machine_data->fsl_diu_info[1]); 1475 fsl_diu_set_par(machine_data->fsl_diu_info[2]); 1476 fsl_diu_set_par(machine_data->fsl_diu_info[3]); 1477 fsl_diu_set_par(machine_data->fsl_diu_info[4]); 1478 } 1479 return count; 1480} 1481 1482static ssize_t show_monitor(struct device *device, 1483 struct device_attribute *attr, char *buf) 1484{ 1485 struct fsl_diu_data *machine_data = 1486 container_of(attr, struct fsl_diu_data, dev_attr); 1487 return diu_ops.show_monitor_port(machine_data->monitor_port, buf); 1488} 1489 1490static int __devinit fsl_diu_probe(struct platform_device *ofdev, 1491 const struct of_device_id *match) 1492{ 1493 struct device_node *np = ofdev->dev.of_node; 1494 struct mfb_info *mfbi; 1495 phys_addr_t dummy_ad_addr; 1496 int ret, i, error = 0; 1497 struct resource res; 1498 struct fsl_diu_data *machine_data; 1499 int diu_mode; 1500 1501 machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); 1502 if (!machine_data) 1503 return -ENOMEM; 1504 1505 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1506 machine_data->fsl_diu_info[i] = 1507 framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); 1508 if (!machine_data->fsl_diu_info[i]) { 1509 dev_err(&ofdev->dev, "cannot allocate memory\n"); 1510 ret = -ENOMEM; 1511 goto error2; 1512 } 1513 mfbi = machine_data->fsl_diu_info[i]->par; 1514 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); 1515 mfbi->parent = machine_data; 1516 1517 if (mfbi->index == 0) { 1518 const u8 *prop; 1519 int len; 1520 1521 /* Get EDID */ 1522 prop = of_get_property(np, "edid", &len); 1523 if (prop && len == EDID_LENGTH) 1524 mfbi->edid_data = kmemdup(prop, EDID_LENGTH, 1525 GFP_KERNEL); 1526 } 1527 } 1528 1529 ret = of_address_to_resource(np, 0, &res); 1530 if (ret) { 1531 dev_err(&ofdev->dev, "could not obtain DIU address\n"); 1532 goto error; 1533 } 1534 if (!res.start) { 1535 dev_err(&ofdev->dev, "invalid DIU address\n"); 1536 goto error; 1537 } 1538 dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); 1539 1540 dr.diu_reg = ioremap(res.start, sizeof(struct diu)); 1541 if (!dr.diu_reg) { 1542 dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); 1543 ret = -EFAULT; 1544 goto error2; 1545 } 1546 1547 diu_mode = in_be32(&dr.diu_reg->diu_mode); 1548 if (diu_mode != MFB_MODE1) 1549 out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */ 1550 1551 /* Get the IRQ of the DIU */ 1552 machine_data->irq = irq_of_parse_and_map(np, 0); 1553 1554 if (!machine_data->irq) { 1555 dev_err(&ofdev->dev, "could not get DIU IRQ\n"); 1556 ret = -EINVAL; 1557 goto error; 1558 } 1559 machine_data->monitor_port = monitor_port; 1560 1561 /* Area descriptor memory pool aligns to 64-bit boundary */ 1562 if (allocate_buf(&ofdev->dev, &pool.ad, 1563 sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) 1564 return -ENOMEM; 1565 1566 /* Get memory for Gamma Table - 32-byte aligned memory */ 1567 if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) { 1568 ret = -ENOMEM; 1569 goto error; 1570 } 1571 1572 /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ 1573 if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1574 32)) { 1575 ret = -ENOMEM; 1576 goto error; 1577 } 1578 1579 i = ARRAY_SIZE(machine_data->fsl_diu_info); 1580 machine_data->dummy_ad = (struct diu_ad *) 1581 ((u32)pool.ad.vaddr + pool.ad.offset) + i; 1582 machine_data->dummy_ad->paddr = pool.ad.paddr + 1583 i * sizeof(struct diu_ad); 1584 machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); 1585 if (!machine_data->dummy_aoi_virt) { 1586 ret = -ENOMEM; 1587 goto error; 1588 } 1589 machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); 1590 machine_data->dummy_ad->pix_fmt = 0x88882317; 1591 machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); 1592 machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); 1593 machine_data->dummy_ad->offset_xyi = 0; 1594 machine_data->dummy_ad->offset_xyd = 0; 1595 machine_data->dummy_ad->next_ad = 0; 1596 1597 /* 1598 * Let DIU display splash screen if it was pre-initialized 1599 * by the bootloader, set dummy area descriptor otherwise. 1600 */ 1601 if (diu_mode != MFB_MODE1) 1602 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); 1603 1604 out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); 1605 out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); 1606 1607 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1608 machine_data->fsl_diu_info[i]->fix.smem_start = 0; 1609 mfbi = machine_data->fsl_diu_info[i]->par; 1610 mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr 1611 + pool.ad.offset) + i; 1612 mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); 1613 ret = install_fb(machine_data->fsl_diu_info[i]); 1614 if (ret) { 1615 dev_err(&ofdev->dev, 1616 "Failed to register framebuffer %d\n", 1617 i); 1618 goto error; 1619 } 1620 } 1621 1622 if (request_irq_local(machine_data->irq)) { 1623 dev_err(machine_data->fsl_diu_info[0]->dev, 1624 "could not request irq for diu."); 1625 goto error; 1626 } 1627 1628 sysfs_attr_init(&machine_data->dev_attr.attr); 1629 machine_data->dev_attr.attr.name = "monitor"; 1630 machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; 1631 machine_data->dev_attr.show = show_monitor; 1632 machine_data->dev_attr.store = store_monitor; 1633 error = device_create_file(machine_data->fsl_diu_info[0]->dev, 1634 &machine_data->dev_attr); 1635 if (error) { 1636 dev_err(machine_data->fsl_diu_info[0]->dev, 1637 "could not create sysfs %s file\n", 1638 machine_data->dev_attr.attr.name); 1639 } 1640 1641 dev_set_drvdata(&ofdev->dev, machine_data); 1642 return 0; 1643 1644error: 1645 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); 1646 i > 0; i--) 1647 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1648 if (pool.ad.vaddr) 1649 free_buf(&ofdev->dev, &pool.ad, 1650 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1651 if (pool.gamma.vaddr) 1652 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1653 if (pool.cursor.vaddr) 1654 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1655 32); 1656 if (machine_data->dummy_aoi_virt) 1657 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1658 iounmap(dr.diu_reg); 1659 1660error2: 1661 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1662 if (machine_data->fsl_diu_info[i]) 1663 framebuffer_release(machine_data->fsl_diu_info[i]); 1664 kfree(machine_data); 1665 1666 return ret; 1667} 1668 1669 1670static int fsl_diu_remove(struct platform_device *ofdev) 1671{ 1672 struct fsl_diu_data *machine_data; 1673 int i; 1674 1675 machine_data = dev_get_drvdata(&ofdev->dev); 1676 disable_lcdc(machine_data->fsl_diu_info[0]); 1677 free_irq_local(machine_data->irq); 1678 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) 1679 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1680 if (pool.ad.vaddr) 1681 free_buf(&ofdev->dev, &pool.ad, 1682 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1683 if (pool.gamma.vaddr) 1684 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1685 if (pool.cursor.vaddr) 1686 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1687 32); 1688 if (machine_data->dummy_aoi_virt) 1689 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1690 iounmap(dr.diu_reg); 1691 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1692 if (machine_data->fsl_diu_info[i]) 1693 framebuffer_release(machine_data->fsl_diu_info[i]); 1694 kfree(machine_data); 1695 1696 return 0; 1697} 1698 1699#ifndef MODULE 1700static int __init fsl_diu_setup(char *options) 1701{ 1702 char *opt; 1703 unsigned long val; 1704 1705 if (!options || !*options) 1706 return 0; 1707 1708 while ((opt = strsep(&options, ",")) != NULL) { 1709 if (!*opt) 1710 continue; 1711 if (!strncmp(opt, "monitor=", 8)) { 1712 if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) 1713 monitor_port = val; 1714 } else if (!strncmp(opt, "bpp=", 4)) { 1715 if (!strict_strtoul(opt + 4, 10, &val)) 1716 default_bpp = val; 1717 } else 1718 fb_mode = opt; 1719 } 1720 1721 return 0; 1722} 1723#endif 1724 1725static struct of_device_id fsl_diu_match[] = { 1726#ifdef CONFIG_PPC_MPC512x 1727 { 1728 .compatible = "fsl,mpc5121-diu", 1729 }, 1730#endif 1731 { 1732 .compatible = "fsl,diu", 1733 }, 1734 {} 1735}; 1736MODULE_DEVICE_TABLE(of, fsl_diu_match); 1737 1738static struct of_platform_driver fsl_diu_driver = { 1739 .driver = { 1740 .name = "fsl_diu", 1741 .owner = THIS_MODULE, 1742 .of_match_table = fsl_diu_match, 1743 }, 1744 .probe = fsl_diu_probe, 1745 .remove = fsl_diu_remove, 1746 .suspend = fsl_diu_suspend, 1747 .resume = fsl_diu_resume, 1748}; 1749 1750static int __init fsl_diu_init(void) 1751{ 1752#ifdef CONFIG_NOT_COHERENT_CACHE 1753 struct device_node *np; 1754 const u32 *prop; 1755#endif 1756 int ret; 1757#ifndef MODULE 1758 char *option; 1759 1760 /* 1761 * For kernel boot options (in 'video=xxxfb:<options>' format) 1762 */ 1763 if (fb_get_options("fslfb", &option)) 1764 return -ENODEV; 1765 fsl_diu_setup(option); 1766#endif 1767 printk(KERN_INFO "Freescale DIU driver\n"); 1768 1769#ifdef CONFIG_NOT_COHERENT_CACHE 1770 np = of_find_node_by_type(NULL, "cpu"); 1771 if (!np) { 1772 printk(KERN_ERR "Err: can't find device node 'cpu'\n"); 1773 return -ENODEV; 1774 } 1775 1776 prop = of_get_property(np, "d-cache-size", NULL); 1777 if (prop == NULL) { 1778 of_node_put(np); 1779 return -ENODEV; 1780 } 1781 1782 /* Freescale PLRU requires 13/8 times the cache size to do a proper 1783 displacement flush 1784 */ 1785 coherence_data_size = *prop * 13; 1786 coherence_data_size /= 8; 1787 1788 prop = of_get_property(np, "d-cache-line-size", NULL); 1789 if (prop == NULL) { 1790 of_node_put(np); 1791 return -ENODEV; 1792 } 1793 d_cache_line_size = *prop; 1794 1795 of_node_put(np); 1796 coherence_data = vmalloc(coherence_data_size); 1797 if (!coherence_data) 1798 return -ENOMEM; 1799#endif 1800 ret = of_register_platform_driver(&fsl_diu_driver); 1801 if (ret) { 1802 printk(KERN_ERR 1803 "fsl-diu: failed to register platform driver\n"); 1804#if defined(CONFIG_NOT_COHERENT_CACHE) 1805 vfree(coherence_data); 1806#endif 1807 iounmap(dr.diu_reg); 1808 } 1809 return ret; 1810} 1811 1812static void __exit fsl_diu_exit(void) 1813{ 1814 of_unregister_platform_driver(&fsl_diu_driver); 1815#if defined(CONFIG_NOT_COHERENT_CACHE) 1816 vfree(coherence_data); 1817#endif 1818} 1819 1820module_init(fsl_diu_init); 1821module_exit(fsl_diu_exit); 1822 1823MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); 1824MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); 1825MODULE_LICENSE("GPL"); 1826 1827module_param_named(mode, fb_mode, charp, 0); 1828MODULE_PARM_DESC(mode, 1829 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 1830module_param_named(bpp, default_bpp, ulong, 0); 1831MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); 1832module_param_named(monitor, monitor_port, int, 0); 1833MODULE_PARM_DESC(monitor, 1834 "Specify the monitor port (0, 1 or 2) if supported by the platform"); 1835