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