Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc9 1818 lines 47 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 pr_debug("check_var xres: %d\n", var->xres); 559 pr_debug("check_var yres: %d\n", var->yres); 560 561 if (var->xres_virtual < var->xres) 562 var->xres_virtual = var->xres; 563 if (var->yres_virtual < var->yres) 564 var->yres_virtual = var->yres; 565 566 if (var->xoffset < 0) 567 var->xoffset = 0; 568 569 if (var->yoffset < 0) 570 var->yoffset = 0; 571 572 if (var->xoffset + info->var.xres > info->var.xres_virtual) 573 var->xoffset = info->var.xres_virtual - info->var.xres; 574 575 if (var->yoffset + info->var.yres > info->var.yres_virtual) 576 var->yoffset = info->var.yres_virtual - info->var.yres; 577 578 if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && 579 (var->bits_per_pixel != 16)) 580 var->bits_per_pixel = default_bpp; 581 582 switch (var->bits_per_pixel) { 583 case 16: 584 var->red.length = 5; 585 var->red.offset = 11; 586 var->red.msb_right = 0; 587 588 var->green.length = 6; 589 var->green.offset = 5; 590 var->green.msb_right = 0; 591 592 var->blue.length = 5; 593 var->blue.offset = 0; 594 var->blue.msb_right = 0; 595 596 var->transp.length = 0; 597 var->transp.offset = 0; 598 var->transp.msb_right = 0; 599 break; 600 case 24: 601 var->red.length = 8; 602 var->red.offset = 0; 603 var->red.msb_right = 0; 604 605 var->green.length = 8; 606 var->green.offset = 8; 607 var->green.msb_right = 0; 608 609 var->blue.length = 8; 610 var->blue.offset = 16; 611 var->blue.msb_right = 0; 612 613 var->transp.length = 0; 614 var->transp.offset = 0; 615 var->transp.msb_right = 0; 616 break; 617 case 32: 618 var->red.length = 8; 619 var->red.offset = 16; 620 var->red.msb_right = 0; 621 622 var->green.length = 8; 623 var->green.offset = 8; 624 var->green.msb_right = 0; 625 626 var->blue.length = 8; 627 var->blue.offset = 0; 628 var->blue.msb_right = 0; 629 630 var->transp.length = 8; 631 var->transp.offset = 24; 632 var->transp.msb_right = 0; 633 634 break; 635 } 636 637 var->height = -1; 638 var->width = -1; 639 var->grayscale = 0; 640 641 /* Copy nonstd field to/from sync for fbset usage */ 642 var->sync |= var->nonstd; 643 var->nonstd |= var->sync; 644 645 adjust_aoi_size_position(var, info); 646 return 0; 647} 648 649static void set_fix(struct fb_info *info) 650{ 651 struct fb_fix_screeninfo *fix = &info->fix; 652 struct fb_var_screeninfo *var = &info->var; 653 struct mfb_info *mfbi = info->par; 654 655 strncpy(fix->id, mfbi->id, strlen(mfbi->id)); 656 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; 657 fix->type = FB_TYPE_PACKED_PIXELS; 658 fix->accel = FB_ACCEL_NONE; 659 fix->visual = FB_VISUAL_TRUECOLOR; 660 fix->xpanstep = 1; 661 fix->ypanstep = 1; 662} 663 664static void update_lcdc(struct fb_info *info) 665{ 666 struct fb_var_screeninfo *var = &info->var; 667 struct mfb_info *mfbi = info->par; 668 struct fsl_diu_data *machine_data = mfbi->parent; 669 struct diu *hw; 670 int i, j; 671 char __iomem *cursor_base, *gamma_table_base; 672 673 u32 temp; 674 675 hw = dr.diu_reg; 676 677 if (mfbi->type == MFB_TYPE_OFF) { 678 fsl_diu_disable_panel(info); 679 return; 680 } 681 682 diu_ops.set_monitor_port(machine_data->monitor_port); 683 gamma_table_base = pool.gamma.vaddr; 684 cursor_base = pool.cursor.vaddr; 685 /* Prep for DIU init - gamma table, cursor table */ 686 687 for (i = 0; i <= 2; i++) 688 for (j = 0; j <= 255; j++) 689 *gamma_table_base++ = j; 690 691 diu_ops.set_gamma_table(machine_data->monitor_port, pool.gamma.vaddr); 692 693 pr_debug("update-lcdc: HW - %p\n Disabling DIU\n", hw); 694 disable_lcdc(info); 695 696 /* Program DIU registers */ 697 698 out_be32(&hw->gamma, pool.gamma.paddr); 699 out_be32(&hw->cursor, pool.cursor.paddr); 700 701 out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ 702 out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ 703 out_be32(&hw->disp_size, (var->yres << 16 | var->xres)); 704 /* DISP SIZE */ 705 pr_debug("DIU xres: %d\n", var->xres); 706 pr_debug("DIU yres: %d\n", var->yres); 707 708 out_be32(&hw->wb_size, 0); /* WB SIZE */ 709 out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ 710 711 /* Horizontal and vertical configuration register */ 712 temp = var->left_margin << 22 | /* BP_H */ 713 var->hsync_len << 11 | /* PW_H */ 714 var->right_margin; /* FP_H */ 715 716 out_be32(&hw->hsyn_para, temp); 717 718 temp = var->upper_margin << 22 | /* BP_V */ 719 var->vsync_len << 11 | /* PW_V */ 720 var->lower_margin; /* FP_V */ 721 722 out_be32(&hw->vsyn_para, temp); 723 724 pr_debug("DIU right_margin - %d\n", var->right_margin); 725 pr_debug("DIU left_margin - %d\n", var->left_margin); 726 pr_debug("DIU hsync_len - %d\n", var->hsync_len); 727 pr_debug("DIU upper_margin - %d\n", var->upper_margin); 728 pr_debug("DIU lower_margin - %d\n", var->lower_margin); 729 pr_debug("DIU vsync_len - %d\n", var->vsync_len); 730 pr_debug("DIU HSYNC - 0x%08x\n", hw->hsyn_para); 731 pr_debug("DIU VSYNC - 0x%08x\n", hw->vsyn_para); 732 733 diu_ops.set_pixel_clock(var->pixclock); 734 735 out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ 736 out_be32(&hw->thresholds, 0x00037800); /* The Thresholds */ 737 out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ 738 out_be32(&hw->plut, 0x01F5F666); 739 740 /* Enable the DIU */ 741 enable_lcdc(info); 742} 743 744static int map_video_memory(struct fb_info *info) 745{ 746 phys_addr_t phys; 747 u32 smem_len = info->fix.line_length * info->var.yres_virtual; 748 749 pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); 750 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 751 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 752 pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len); 753 754 info->screen_base = fsl_diu_alloc(smem_len, &phys); 755 if (info->screen_base == NULL) { 756 printk(KERN_ERR "Unable to allocate fb memory\n"); 757 return -ENOMEM; 758 } 759 mutex_lock(&info->mm_lock); 760 info->fix.smem_start = (unsigned long) phys; 761 info->fix.smem_len = smem_len; 762 mutex_unlock(&info->mm_lock); 763 info->screen_size = info->fix.smem_len; 764 765 pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", 766 info->fix.smem_start, info->fix.smem_len); 767 pr_debug("screen base %p\n", info->screen_base); 768 769 return 0; 770} 771 772static void unmap_video_memory(struct fb_info *info) 773{ 774 fsl_diu_free(info->screen_base, info->fix.smem_len); 775 mutex_lock(&info->mm_lock); 776 info->screen_base = NULL; 777 info->fix.smem_start = 0; 778 info->fix.smem_len = 0; 779 mutex_unlock(&info->mm_lock); 780} 781 782/* 783 * Using the fb_var_screeninfo in fb_info we set the aoi of this 784 * particular framebuffer. It is a light version of fsl_diu_set_par. 785 */ 786static int fsl_diu_set_aoi(struct fb_info *info) 787{ 788 struct fb_var_screeninfo *var = &info->var; 789 struct mfb_info *mfbi = info->par; 790 struct diu_ad *ad = mfbi->ad; 791 792 /* AOI should not be greater than display size */ 793 ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); 794 ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); 795 return 0; 796} 797 798/* 799 * Using the fb_var_screeninfo in fb_info we set the resolution of this 800 * particular framebuffer. This function alters the fb_fix_screeninfo stored 801 * in fb_info. It does not alter var in fb_info since we are using that 802 * data. This means we depend on the data in var inside fb_info to be 803 * supported by the hardware. fsl_diu_check_var is always called before 804 * fsl_diu_set_par to ensure this. 805 */ 806static int fsl_diu_set_par(struct fb_info *info) 807{ 808 unsigned long len; 809 struct fb_var_screeninfo *var = &info->var; 810 struct mfb_info *mfbi = info->par; 811 struct fsl_diu_data *machine_data = mfbi->parent; 812 struct diu_ad *ad = mfbi->ad; 813 struct diu *hw; 814 815 hw = dr.diu_reg; 816 817 set_fix(info); 818 mfbi->cursor_reset = 1; 819 820 len = info->var.yres_virtual * info->fix.line_length; 821 /* Alloc & dealloc each time resolution/bpp change */ 822 if (len != info->fix.smem_len) { 823 if (info->fix.smem_start) 824 unmap_video_memory(info); 825 pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len); 826 827 /* Memory allocation for framebuffer */ 828 if (map_video_memory(info)) { 829 printk(KERN_ERR "Unable to allocate fb memory 1\n"); 830 return -ENOMEM; 831 } 832 } 833 834 ad->pix_fmt = 835 diu_ops.get_pixel_format(var->bits_per_pixel, 836 machine_data->monitor_port); 837 ad->addr = cpu_to_le32(info->fix.smem_start); 838 ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | 839 var->xres_virtual) | mfbi->g_alpha; 840 /* AOI should not be greater than display size */ 841 ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); 842 ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); 843 ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); 844 845 /* Disable chroma keying function */ 846 ad->ckmax_r = 0; 847 ad->ckmax_g = 0; 848 ad->ckmax_b = 0; 849 850 ad->ckmin_r = 255; 851 ad->ckmin_g = 255; 852 ad->ckmin_b = 255; 853 854 if (mfbi->index == 0) 855 update_lcdc(info); 856 return 0; 857} 858 859static inline __u32 CNVT_TOHW(__u32 val, __u32 width) 860{ 861 return ((val<<width) + 0x7FFF - val)>>16; 862} 863 864/* 865 * Set a single color register. The values supplied have a 16 bit magnitude 866 * which needs to be scaled in this function for the hardware. Things to take 867 * into consideration are how many color registers, if any, are supported with 868 * the current color visual. With truecolor mode no color palettes are 869 * supported. Here a pseudo palette is created which we store the value in 870 * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited 871 * color palette. 872 */ 873static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green, 874 unsigned blue, unsigned transp, struct fb_info *info) 875{ 876 int ret = 1; 877 878 /* 879 * If greyscale is true, then we convert the RGB value 880 * to greyscale no matter what visual we are using. 881 */ 882 if (info->var.grayscale) 883 red = green = blue = (19595 * red + 38470 * green + 884 7471 * blue) >> 16; 885 switch (info->fix.visual) { 886 case FB_VISUAL_TRUECOLOR: 887 /* 888 * 16-bit True Colour. We encode the RGB value 889 * according to the RGB bitfield information. 890 */ 891 if (regno < 16) { 892 u32 *pal = info->pseudo_palette; 893 u32 v; 894 895 red = CNVT_TOHW(red, info->var.red.length); 896 green = CNVT_TOHW(green, info->var.green.length); 897 blue = CNVT_TOHW(blue, info->var.blue.length); 898 transp = CNVT_TOHW(transp, info->var.transp.length); 899 900 v = (red << info->var.red.offset) | 901 (green << info->var.green.offset) | 902 (blue << info->var.blue.offset) | 903 (transp << info->var.transp.offset); 904 905 pal[regno] = v; 906 ret = 0; 907 } 908 break; 909 case FB_VISUAL_STATIC_PSEUDOCOLOR: 910 case FB_VISUAL_PSEUDOCOLOR: 911 break; 912 } 913 914 return ret; 915} 916 917/* 918 * Pan (or wrap, depending on the `vmode' field) the display using the 919 * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values 920 * don't fit, return -EINVAL. 921 */ 922static int fsl_diu_pan_display(struct fb_var_screeninfo *var, 923 struct fb_info *info) 924{ 925 if ((info->var.xoffset == var->xoffset) && 926 (info->var.yoffset == var->yoffset)) 927 return 0; /* No change, do nothing */ 928 929 if (var->xoffset < 0 || var->yoffset < 0 930 || var->xoffset + info->var.xres > info->var.xres_virtual 931 || var->yoffset + info->var.yres > info->var.yres_virtual) 932 return -EINVAL; 933 934 info->var.xoffset = var->xoffset; 935 info->var.yoffset = var->yoffset; 936 937 if (var->vmode & FB_VMODE_YWRAP) 938 info->var.vmode |= FB_VMODE_YWRAP; 939 else 940 info->var.vmode &= ~FB_VMODE_YWRAP; 941 942 fsl_diu_set_aoi(info); 943 944 return 0; 945} 946 947/* 948 * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking 949 * succeeded, != 0 if un-/blanking failed. 950 * blank_mode == 2: suspend vsync 951 * blank_mode == 3: suspend hsync 952 * blank_mode == 4: powerdown 953 */ 954static int fsl_diu_blank(int blank_mode, struct fb_info *info) 955{ 956 struct mfb_info *mfbi = info->par; 957 958 mfbi->blank = blank_mode; 959 960 switch (blank_mode) { 961 case FB_BLANK_VSYNC_SUSPEND: 962 case FB_BLANK_HSYNC_SUSPEND: 963 /* FIXME: fixes to enable_panel and enable lcdc needed */ 964 case FB_BLANK_NORMAL: 965 /* fsl_diu_disable_panel(info);*/ 966 break; 967 case FB_BLANK_POWERDOWN: 968 /* disable_lcdc(info); */ 969 break; 970 case FB_BLANK_UNBLANK: 971 /* fsl_diu_enable_panel(info);*/ 972 break; 973 } 974 975 return 0; 976} 977 978static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, 979 unsigned long arg) 980{ 981 struct mfb_info *mfbi = info->par; 982 struct diu_ad *ad = mfbi->ad; 983 struct mfb_chroma_key ck; 984 unsigned char global_alpha; 985 struct aoi_display_offset aoi_d; 986 __u32 pix_fmt; 987 void __user *buf = (void __user *)arg; 988 989 if (!arg) 990 return -EINVAL; 991 switch (cmd) { 992 case MFB_SET_PIXFMT: 993 if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) 994 return -EFAULT; 995 ad->pix_fmt = pix_fmt; 996 pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); 997 break; 998 case MFB_GET_PIXFMT: 999 pix_fmt = ad->pix_fmt; 1000 if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) 1001 return -EFAULT; 1002 pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); 1003 break; 1004 case MFB_SET_AOID: 1005 if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) 1006 return -EFAULT; 1007 mfbi->x_aoi_d = aoi_d.x_aoi_d; 1008 mfbi->y_aoi_d = aoi_d.y_aoi_d; 1009 pr_debug("set AOI display offset of index %d to (%d,%d)\n", 1010 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1011 fsl_diu_check_var(&info->var, info); 1012 fsl_diu_set_aoi(info); 1013 break; 1014 case MFB_GET_AOID: 1015 aoi_d.x_aoi_d = mfbi->x_aoi_d; 1016 aoi_d.y_aoi_d = mfbi->y_aoi_d; 1017 if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) 1018 return -EFAULT; 1019 pr_debug("get AOI display offset of index %d (%d,%d)\n", 1020 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1021 break; 1022 case MFB_GET_ALPHA: 1023 global_alpha = mfbi->g_alpha; 1024 if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) 1025 return -EFAULT; 1026 pr_debug("get global alpha of index %d\n", mfbi->index); 1027 break; 1028 case MFB_SET_ALPHA: 1029 /* set panel information */ 1030 if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) 1031 return -EFAULT; 1032 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | 1033 (global_alpha & 0xff); 1034 mfbi->g_alpha = global_alpha; 1035 pr_debug("set global alpha for index %d\n", mfbi->index); 1036 break; 1037 case MFB_SET_CHROMA_KEY: 1038 /* set panel winformation */ 1039 if (copy_from_user(&ck, buf, sizeof(ck))) 1040 return -EFAULT; 1041 1042 if (ck.enable && 1043 (ck.red_max < ck.red_min || 1044 ck.green_max < ck.green_min || 1045 ck.blue_max < ck.blue_min)) 1046 return -EINVAL; 1047 1048 if (!ck.enable) { 1049 ad->ckmax_r = 0; 1050 ad->ckmax_g = 0; 1051 ad->ckmax_b = 0; 1052 ad->ckmin_r = 255; 1053 ad->ckmin_g = 255; 1054 ad->ckmin_b = 255; 1055 } else { 1056 ad->ckmax_r = ck.red_max; 1057 ad->ckmax_g = ck.green_max; 1058 ad->ckmax_b = ck.blue_max; 1059 ad->ckmin_r = ck.red_min; 1060 ad->ckmin_g = ck.green_min; 1061 ad->ckmin_b = ck.blue_min; 1062 } 1063 pr_debug("set chroma key\n"); 1064 break; 1065 case FBIOGET_GWINFO: 1066 if (mfbi->type == MFB_TYPE_OFF) 1067 return -ENODEV; 1068 /* get graphic window information */ 1069 if (copy_to_user(buf, ad, sizeof(*ad))) 1070 return -EFAULT; 1071 break; 1072 case FBIOGET_HWCINFO: 1073 pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); 1074 break; 1075 case FBIOPUT_MODEINFO: 1076 pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); 1077 break; 1078 case FBIOGET_DISPINFO: 1079 pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); 1080 break; 1081 1082 default: 1083 printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); 1084 return -ENOIOCTLCMD; 1085 } 1086 1087 return 0; 1088} 1089 1090/* turn on fb if count == 1 1091 */ 1092static int fsl_diu_open(struct fb_info *info, int user) 1093{ 1094 struct mfb_info *mfbi = info->par; 1095 int res = 0; 1096 1097 /* free boot splash memory on first /dev/fb0 open */ 1098 if (!mfbi->index && diu_ops.release_bootmem) 1099 diu_ops.release_bootmem(); 1100 1101 spin_lock(&diu_lock); 1102 mfbi->count++; 1103 if (mfbi->count == 1) { 1104 pr_debug("open plane index %d\n", mfbi->index); 1105 fsl_diu_check_var(&info->var, info); 1106 res = fsl_diu_set_par(info); 1107 if (res < 0) 1108 mfbi->count--; 1109 else { 1110 res = fsl_diu_enable_panel(info); 1111 if (res < 0) 1112 mfbi->count--; 1113 } 1114 } 1115 1116 spin_unlock(&diu_lock); 1117 return res; 1118} 1119 1120/* turn off fb if count == 0 1121 */ 1122static int fsl_diu_release(struct fb_info *info, int user) 1123{ 1124 struct mfb_info *mfbi = info->par; 1125 int res = 0; 1126 1127 spin_lock(&diu_lock); 1128 mfbi->count--; 1129 if (mfbi->count == 0) { 1130 pr_debug("release plane index %d\n", mfbi->index); 1131 res = fsl_diu_disable_panel(info); 1132 if (res < 0) 1133 mfbi->count++; 1134 } 1135 spin_unlock(&diu_lock); 1136 return res; 1137} 1138 1139static struct fb_ops fsl_diu_ops = { 1140 .owner = THIS_MODULE, 1141 .fb_check_var = fsl_diu_check_var, 1142 .fb_set_par = fsl_diu_set_par, 1143 .fb_setcolreg = fsl_diu_setcolreg, 1144 .fb_blank = fsl_diu_blank, 1145 .fb_pan_display = fsl_diu_pan_display, 1146 .fb_fillrect = cfb_fillrect, 1147 .fb_copyarea = cfb_copyarea, 1148 .fb_imageblit = cfb_imageblit, 1149 .fb_ioctl = fsl_diu_ioctl, 1150 .fb_open = fsl_diu_open, 1151 .fb_release = fsl_diu_release, 1152}; 1153 1154static int init_fbinfo(struct fb_info *info) 1155{ 1156 struct mfb_info *mfbi = info->par; 1157 1158 info->device = NULL; 1159 info->var.activate = FB_ACTIVATE_NOW; 1160 info->fbops = &fsl_diu_ops; 1161 info->flags = FBINFO_FLAG_DEFAULT; 1162 info->pseudo_palette = &mfbi->pseudo_palette; 1163 1164 /* Allocate colormap */ 1165 fb_alloc_cmap(&info->cmap, 16, 0); 1166 return 0; 1167} 1168 1169static int __devinit install_fb(struct fb_info *info) 1170{ 1171 int rc; 1172 struct mfb_info *mfbi = info->par; 1173 const char *aoi_mode, *init_aoi_mode = "320x240"; 1174 struct fb_videomode *db = fsl_diu_mode_db; 1175 unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); 1176 int has_default_mode = 1; 1177 1178 if (init_fbinfo(info)) 1179 return -EINVAL; 1180 1181 if (mfbi->index == 0) { /* plane 0 */ 1182 if (mfbi->edid_data) { 1183 /* Now build modedb from EDID */ 1184 fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs); 1185 fb_videomode_to_modelist(info->monspecs.modedb, 1186 info->monspecs.modedb_len, 1187 &info->modelist); 1188 db = info->monspecs.modedb; 1189 dbsize = info->monspecs.modedb_len; 1190 } 1191 aoi_mode = fb_mode; 1192 } else { 1193 aoi_mode = init_aoi_mode; 1194 } 1195 pr_debug("mode used = %s\n", aoi_mode); 1196 rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, 1197 &fsl_diu_default_mode, default_bpp); 1198 switch (rc) { 1199 case 1: 1200 pr_debug("using mode specified in @mode\n"); 1201 break; 1202 case 2: 1203 pr_debug("using mode specified in @mode " 1204 "with ignored refresh rate\n"); 1205 break; 1206 case 3: 1207 pr_debug("using mode default mode\n"); 1208 break; 1209 case 4: 1210 pr_debug("using mode from list\n"); 1211 break; 1212 default: 1213 pr_debug("rc = %d\n", rc); 1214 pr_debug("failed to find mode\n"); 1215 /* 1216 * For plane 0 we continue and look into 1217 * driver's internal modedb. 1218 */ 1219 if (mfbi->index == 0 && mfbi->edid_data) 1220 has_default_mode = 0; 1221 else 1222 return -EINVAL; 1223 break; 1224 } 1225 1226 if (!has_default_mode) { 1227 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, 1228 ARRAY_SIZE(fsl_diu_mode_db), 1229 &fsl_diu_default_mode, 1230 default_bpp); 1231 if (rc > 0 && rc < 5) 1232 has_default_mode = 1; 1233 } 1234 1235 /* Still not found, use preferred mode from database if any */ 1236 if (!has_default_mode && info->monspecs.modedb) { 1237 struct fb_monspecs *specs = &info->monspecs; 1238 struct fb_videomode *modedb = &specs->modedb[0]; 1239 1240 /* 1241 * Get preferred timing. If not found, 1242 * first mode in database will be used. 1243 */ 1244 if (specs->misc & FB_MISC_1ST_DETAIL) { 1245 int i; 1246 1247 for (i = 0; i < specs->modedb_len; i++) { 1248 if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { 1249 modedb = &specs->modedb[i]; 1250 break; 1251 } 1252 } 1253 } 1254 1255 info->var.bits_per_pixel = default_bpp; 1256 fb_videomode_to_var(&info->var, modedb); 1257 } 1258 1259 pr_debug("xres_virtual %d\n", info->var.xres_virtual); 1260 pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); 1261 1262 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 1263 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 1264 1265 if (mfbi->type == MFB_TYPE_OFF) 1266 mfbi->blank = FB_BLANK_NORMAL; 1267 else 1268 mfbi->blank = FB_BLANK_UNBLANK; 1269 1270 if (fsl_diu_check_var(&info->var, info)) { 1271 printk(KERN_ERR "fb_check_var failed"); 1272 fb_dealloc_cmap(&info->cmap); 1273 return -EINVAL; 1274 } 1275 1276 if (register_framebuffer(info) < 0) { 1277 printk(KERN_ERR "register_framebuffer failed"); 1278 unmap_video_memory(info); 1279 fb_dealloc_cmap(&info->cmap); 1280 return -EINVAL; 1281 } 1282 1283 mfbi->registered = 1; 1284 printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", 1285 info->node, info->fix.id); 1286 1287 return 0; 1288} 1289 1290static void uninstall_fb(struct fb_info *info) 1291{ 1292 struct mfb_info *mfbi = info->par; 1293 1294 if (!mfbi->registered) 1295 return; 1296 1297 if (mfbi->index == 0) 1298 kfree(mfbi->edid_data); 1299 1300 unregister_framebuffer(info); 1301 unmap_video_memory(info); 1302 if (&info->cmap) 1303 fb_dealloc_cmap(&info->cmap); 1304 1305 mfbi->registered = 0; 1306} 1307 1308static irqreturn_t fsl_diu_isr(int irq, void *dev_id) 1309{ 1310 struct diu *hw = dr.diu_reg; 1311 unsigned int status = in_be32(&hw->int_status); 1312 1313 if (status) { 1314 /* This is the workaround for underrun */ 1315 if (status & INT_UNDRUN) { 1316 out_be32(&hw->diu_mode, 0); 1317 pr_debug("Err: DIU occurs underrun!\n"); 1318 udelay(1); 1319 out_be32(&hw->diu_mode, 1); 1320 } 1321#if defined(CONFIG_NOT_COHERENT_CACHE) 1322 else if (status & INT_VSYNC) { 1323 unsigned int i; 1324 for (i = 0; i < coherence_data_size; 1325 i += d_cache_line_size) 1326 __asm__ __volatile__ ( 1327 "dcbz 0, %[input]" 1328 ::[input]"r"(&coherence_data[i])); 1329 } 1330#endif 1331 return IRQ_HANDLED; 1332 } 1333 return IRQ_NONE; 1334} 1335 1336static int request_irq_local(int irq) 1337{ 1338 unsigned long status, ints; 1339 struct diu *hw; 1340 int ret; 1341 1342 hw = dr.diu_reg; 1343 1344 /* Read to clear the status */ 1345 status = in_be32(&hw->int_status); 1346 1347 ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL); 1348 if (ret) 1349 pr_info("Request diu IRQ failed.\n"); 1350 else { 1351 ints = INT_PARERR | INT_LS_BF_VS; 1352#if !defined(CONFIG_NOT_COHERENT_CACHE) 1353 ints |= INT_VSYNC; 1354#endif 1355 if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) 1356 ints |= INT_VSYNC_WB; 1357 1358 /* Read to clear the status */ 1359 status = in_be32(&hw->int_status); 1360 out_be32(&hw->int_mask, ints); 1361 } 1362 return ret; 1363} 1364 1365static void free_irq_local(int irq) 1366{ 1367 struct diu *hw = dr.diu_reg; 1368 1369 /* Disable all LCDC interrupt */ 1370 out_be32(&hw->int_mask, 0x1f); 1371 1372 free_irq(irq, NULL); 1373} 1374 1375#ifdef CONFIG_PM 1376/* 1377 * Power management hooks. Note that we won't be called from IRQ context, 1378 * unlike the blank functions above, so we may sleep. 1379 */ 1380static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) 1381{ 1382 struct fsl_diu_data *machine_data; 1383 1384 machine_data = dev_get_drvdata(&ofdev->dev); 1385 disable_lcdc(machine_data->fsl_diu_info[0]); 1386 1387 return 0; 1388} 1389 1390static int fsl_diu_resume(struct platform_device *ofdev) 1391{ 1392 struct fsl_diu_data *machine_data; 1393 1394 machine_data = dev_get_drvdata(&ofdev->dev); 1395 enable_lcdc(machine_data->fsl_diu_info[0]); 1396 1397 return 0; 1398} 1399 1400#else 1401#define fsl_diu_suspend NULL 1402#define fsl_diu_resume NULL 1403#endif /* CONFIG_PM */ 1404 1405/* Align to 64-bit(8-byte), 32-byte, etc. */ 1406static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, 1407 u32 bytes_align) 1408{ 1409 u32 offset, ssize; 1410 u32 mask; 1411 dma_addr_t paddr = 0; 1412 1413 ssize = size + bytes_align; 1414 buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA | 1415 __GFP_ZERO); 1416 if (!buf->vaddr) 1417 return -ENOMEM; 1418 1419 buf->paddr = (__u32) paddr; 1420 1421 mask = bytes_align - 1; 1422 offset = (u32)buf->paddr & mask; 1423 if (offset) { 1424 buf->offset = bytes_align - offset; 1425 buf->paddr = (u32)buf->paddr + offset; 1426 } else 1427 buf->offset = 0; 1428 return 0; 1429} 1430 1431static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, 1432 u32 bytes_align) 1433{ 1434 dma_free_coherent(dev, size + bytes_align, 1435 buf->vaddr, (buf->paddr - buf->offset)); 1436 return; 1437} 1438 1439static ssize_t store_monitor(struct device *device, 1440 struct device_attribute *attr, const char *buf, size_t count) 1441{ 1442 int old_monitor_port; 1443 unsigned long val; 1444 struct fsl_diu_data *machine_data = 1445 container_of(attr, struct fsl_diu_data, dev_attr); 1446 1447 if (strict_strtoul(buf, 10, &val)) 1448 return 0; 1449 1450 old_monitor_port = machine_data->monitor_port; 1451 machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); 1452 1453 if (old_monitor_port != machine_data->monitor_port) { 1454 /* All AOIs need adjust pixel format 1455 * fsl_diu_set_par only change the pixsel format here 1456 * unlikely to fail. */ 1457 fsl_diu_set_par(machine_data->fsl_diu_info[0]); 1458 fsl_diu_set_par(machine_data->fsl_diu_info[1]); 1459 fsl_diu_set_par(machine_data->fsl_diu_info[2]); 1460 fsl_diu_set_par(machine_data->fsl_diu_info[3]); 1461 fsl_diu_set_par(machine_data->fsl_diu_info[4]); 1462 } 1463 return count; 1464} 1465 1466static ssize_t show_monitor(struct device *device, 1467 struct device_attribute *attr, char *buf) 1468{ 1469 struct fsl_diu_data *machine_data = 1470 container_of(attr, struct fsl_diu_data, dev_attr); 1471 return diu_ops.show_monitor_port(machine_data->monitor_port, buf); 1472} 1473 1474static int __devinit fsl_diu_probe(struct platform_device *ofdev) 1475{ 1476 struct device_node *np = ofdev->dev.of_node; 1477 struct mfb_info *mfbi; 1478 phys_addr_t dummy_ad_addr; 1479 int ret, i, error = 0; 1480 struct resource res; 1481 struct fsl_diu_data *machine_data; 1482 int diu_mode; 1483 1484 machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); 1485 if (!machine_data) 1486 return -ENOMEM; 1487 1488 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1489 machine_data->fsl_diu_info[i] = 1490 framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); 1491 if (!machine_data->fsl_diu_info[i]) { 1492 dev_err(&ofdev->dev, "cannot allocate memory\n"); 1493 ret = -ENOMEM; 1494 goto error2; 1495 } 1496 mfbi = machine_data->fsl_diu_info[i]->par; 1497 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); 1498 mfbi->parent = machine_data; 1499 1500 if (mfbi->index == 0) { 1501 const u8 *prop; 1502 int len; 1503 1504 /* Get EDID */ 1505 prop = of_get_property(np, "edid", &len); 1506 if (prop && len == EDID_LENGTH) 1507 mfbi->edid_data = kmemdup(prop, EDID_LENGTH, 1508 GFP_KERNEL); 1509 } 1510 } 1511 1512 ret = of_address_to_resource(np, 0, &res); 1513 if (ret) { 1514 dev_err(&ofdev->dev, "could not obtain DIU address\n"); 1515 goto error; 1516 } 1517 if (!res.start) { 1518 dev_err(&ofdev->dev, "invalid DIU address\n"); 1519 goto error; 1520 } 1521 dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); 1522 1523 dr.diu_reg = ioremap(res.start, sizeof(struct diu)); 1524 if (!dr.diu_reg) { 1525 dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); 1526 ret = -EFAULT; 1527 goto error2; 1528 } 1529 1530 diu_mode = in_be32(&dr.diu_reg->diu_mode); 1531 if (diu_mode != MFB_MODE1) 1532 out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */ 1533 1534 /* Get the IRQ of the DIU */ 1535 machine_data->irq = irq_of_parse_and_map(np, 0); 1536 1537 if (!machine_data->irq) { 1538 dev_err(&ofdev->dev, "could not get DIU IRQ\n"); 1539 ret = -EINVAL; 1540 goto error; 1541 } 1542 machine_data->monitor_port = monitor_port; 1543 1544 /* Area descriptor memory pool aligns to 64-bit boundary */ 1545 if (allocate_buf(&ofdev->dev, &pool.ad, 1546 sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) 1547 return -ENOMEM; 1548 1549 /* Get memory for Gamma Table - 32-byte aligned memory */ 1550 if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) { 1551 ret = -ENOMEM; 1552 goto error; 1553 } 1554 1555 /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ 1556 if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1557 32)) { 1558 ret = -ENOMEM; 1559 goto error; 1560 } 1561 1562 i = ARRAY_SIZE(machine_data->fsl_diu_info); 1563 machine_data->dummy_ad = (struct diu_ad *) 1564 ((u32)pool.ad.vaddr + pool.ad.offset) + i; 1565 machine_data->dummy_ad->paddr = pool.ad.paddr + 1566 i * sizeof(struct diu_ad); 1567 machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); 1568 if (!machine_data->dummy_aoi_virt) { 1569 ret = -ENOMEM; 1570 goto error; 1571 } 1572 machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); 1573 machine_data->dummy_ad->pix_fmt = 0x88882317; 1574 machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); 1575 machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); 1576 machine_data->dummy_ad->offset_xyi = 0; 1577 machine_data->dummy_ad->offset_xyd = 0; 1578 machine_data->dummy_ad->next_ad = 0; 1579 1580 /* 1581 * Let DIU display splash screen if it was pre-initialized 1582 * by the bootloader, set dummy area descriptor otherwise. 1583 */ 1584 if (diu_mode != MFB_MODE1) 1585 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); 1586 1587 out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); 1588 out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); 1589 1590 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1591 machine_data->fsl_diu_info[i]->fix.smem_start = 0; 1592 mfbi = machine_data->fsl_diu_info[i]->par; 1593 mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr 1594 + pool.ad.offset) + i; 1595 mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); 1596 ret = install_fb(machine_data->fsl_diu_info[i]); 1597 if (ret) { 1598 dev_err(&ofdev->dev, 1599 "Failed to register framebuffer %d\n", 1600 i); 1601 goto error; 1602 } 1603 } 1604 1605 if (request_irq_local(machine_data->irq)) { 1606 dev_err(machine_data->fsl_diu_info[0]->dev, 1607 "could not request irq for diu."); 1608 goto error; 1609 } 1610 1611 sysfs_attr_init(&machine_data->dev_attr.attr); 1612 machine_data->dev_attr.attr.name = "monitor"; 1613 machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; 1614 machine_data->dev_attr.show = show_monitor; 1615 machine_data->dev_attr.store = store_monitor; 1616 error = device_create_file(machine_data->fsl_diu_info[0]->dev, 1617 &machine_data->dev_attr); 1618 if (error) { 1619 dev_err(machine_data->fsl_diu_info[0]->dev, 1620 "could not create sysfs %s file\n", 1621 machine_data->dev_attr.attr.name); 1622 } 1623 1624 dev_set_drvdata(&ofdev->dev, machine_data); 1625 return 0; 1626 1627error: 1628 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); 1629 i > 0; i--) 1630 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1631 if (pool.ad.vaddr) 1632 free_buf(&ofdev->dev, &pool.ad, 1633 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1634 if (pool.gamma.vaddr) 1635 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1636 if (pool.cursor.vaddr) 1637 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1638 32); 1639 if (machine_data->dummy_aoi_virt) 1640 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1641 iounmap(dr.diu_reg); 1642 1643error2: 1644 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1645 if (machine_data->fsl_diu_info[i]) 1646 framebuffer_release(machine_data->fsl_diu_info[i]); 1647 kfree(machine_data); 1648 1649 return ret; 1650} 1651 1652 1653static int fsl_diu_remove(struct platform_device *ofdev) 1654{ 1655 struct fsl_diu_data *machine_data; 1656 int i; 1657 1658 machine_data = dev_get_drvdata(&ofdev->dev); 1659 disable_lcdc(machine_data->fsl_diu_info[0]); 1660 free_irq_local(machine_data->irq); 1661 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) 1662 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1663 if (pool.ad.vaddr) 1664 free_buf(&ofdev->dev, &pool.ad, 1665 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1666 if (pool.gamma.vaddr) 1667 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1668 if (pool.cursor.vaddr) 1669 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1670 32); 1671 if (machine_data->dummy_aoi_virt) 1672 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1673 iounmap(dr.diu_reg); 1674 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1675 if (machine_data->fsl_diu_info[i]) 1676 framebuffer_release(machine_data->fsl_diu_info[i]); 1677 kfree(machine_data); 1678 1679 return 0; 1680} 1681 1682#ifndef MODULE 1683static int __init fsl_diu_setup(char *options) 1684{ 1685 char *opt; 1686 unsigned long val; 1687 1688 if (!options || !*options) 1689 return 0; 1690 1691 while ((opt = strsep(&options, ",")) != NULL) { 1692 if (!*opt) 1693 continue; 1694 if (!strncmp(opt, "monitor=", 8)) { 1695 if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) 1696 monitor_port = val; 1697 } else if (!strncmp(opt, "bpp=", 4)) { 1698 if (!strict_strtoul(opt + 4, 10, &val)) 1699 default_bpp = val; 1700 } else 1701 fb_mode = opt; 1702 } 1703 1704 return 0; 1705} 1706#endif 1707 1708static struct of_device_id fsl_diu_match[] = { 1709#ifdef CONFIG_PPC_MPC512x 1710 { 1711 .compatible = "fsl,mpc5121-diu", 1712 }, 1713#endif 1714 { 1715 .compatible = "fsl,diu", 1716 }, 1717 {} 1718}; 1719MODULE_DEVICE_TABLE(of, fsl_diu_match); 1720 1721static struct platform_driver fsl_diu_driver = { 1722 .driver = { 1723 .name = "fsl_diu", 1724 .owner = THIS_MODULE, 1725 .of_match_table = fsl_diu_match, 1726 }, 1727 .probe = fsl_diu_probe, 1728 .remove = fsl_diu_remove, 1729 .suspend = fsl_diu_suspend, 1730 .resume = fsl_diu_resume, 1731}; 1732 1733static int __init fsl_diu_init(void) 1734{ 1735#ifdef CONFIG_NOT_COHERENT_CACHE 1736 struct device_node *np; 1737 const u32 *prop; 1738#endif 1739 int ret; 1740#ifndef MODULE 1741 char *option; 1742 1743 /* 1744 * For kernel boot options (in 'video=xxxfb:<options>' format) 1745 */ 1746 if (fb_get_options("fslfb", &option)) 1747 return -ENODEV; 1748 fsl_diu_setup(option); 1749#endif 1750 printk(KERN_INFO "Freescale DIU driver\n"); 1751 1752#ifdef CONFIG_NOT_COHERENT_CACHE 1753 np = of_find_node_by_type(NULL, "cpu"); 1754 if (!np) { 1755 printk(KERN_ERR "Err: can't find device node 'cpu'\n"); 1756 return -ENODEV; 1757 } 1758 1759 prop = of_get_property(np, "d-cache-size", NULL); 1760 if (prop == NULL) { 1761 of_node_put(np); 1762 return -ENODEV; 1763 } 1764 1765 /* Freescale PLRU requires 13/8 times the cache size to do a proper 1766 displacement flush 1767 */ 1768 coherence_data_size = *prop * 13; 1769 coherence_data_size /= 8; 1770 1771 prop = of_get_property(np, "d-cache-line-size", NULL); 1772 if (prop == NULL) { 1773 of_node_put(np); 1774 return -ENODEV; 1775 } 1776 d_cache_line_size = *prop; 1777 1778 of_node_put(np); 1779 coherence_data = vmalloc(coherence_data_size); 1780 if (!coherence_data) 1781 return -ENOMEM; 1782#endif 1783 ret = platform_driver_register(&fsl_diu_driver); 1784 if (ret) { 1785 printk(KERN_ERR 1786 "fsl-diu: failed to register platform driver\n"); 1787#if defined(CONFIG_NOT_COHERENT_CACHE) 1788 vfree(coherence_data); 1789#endif 1790 iounmap(dr.diu_reg); 1791 } 1792 return ret; 1793} 1794 1795static void __exit fsl_diu_exit(void) 1796{ 1797 platform_driver_unregister(&fsl_diu_driver); 1798#if defined(CONFIG_NOT_COHERENT_CACHE) 1799 vfree(coherence_data); 1800#endif 1801} 1802 1803module_init(fsl_diu_init); 1804module_exit(fsl_diu_exit); 1805 1806MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); 1807MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); 1808MODULE_LICENSE("GPL"); 1809 1810module_param_named(mode, fb_mode, charp, 0); 1811MODULE_PARM_DESC(mode, 1812 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 1813module_param_named(bpp, default_bpp, ulong, 0); 1814MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); 1815module_param_named(monitor, monitor_port, int, 0); 1816MODULE_PARM_DESC(monitor, 1817 "Specify the monitor port (0, 1 or 2) if supported by the platform"); 1818