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

Configure Feed

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

at v2.6.30 1740 lines 45 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 "fsl-diu-fb.h" 38 39/* 40 * These parameters give default parameters 41 * for video output 1024x768, 42 * FIXME - change timing to proper amounts 43 * hsync 31.5kHz, vsync 60Hz 44 */ 45static struct fb_videomode __devinitdata fsl_diu_default_mode = { 46 .refresh = 60, 47 .xres = 1024, 48 .yres = 768, 49 .pixclock = 15385, 50 .left_margin = 160, 51 .right_margin = 24, 52 .upper_margin = 29, 53 .lower_margin = 3, 54 .hsync_len = 136, 55 .vsync_len = 6, 56 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 57 .vmode = FB_VMODE_NONINTERLACED 58}; 59 60static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { 61 { 62 .name = "1024x768-60", 63 .refresh = 60, 64 .xres = 1024, 65 .yres = 768, 66 .pixclock = 15385, 67 .left_margin = 160, 68 .right_margin = 24, 69 .upper_margin = 29, 70 .lower_margin = 3, 71 .hsync_len = 136, 72 .vsync_len = 6, 73 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 74 .vmode = FB_VMODE_NONINTERLACED 75 }, 76 { 77 .name = "1024x768-70", 78 .refresh = 70, 79 .xres = 1024, 80 .yres = 768, 81 .pixclock = 16886, 82 .left_margin = 3, 83 .right_margin = 3, 84 .upper_margin = 2, 85 .lower_margin = 2, 86 .hsync_len = 40, 87 .vsync_len = 18, 88 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 89 .vmode = FB_VMODE_NONINTERLACED 90 }, 91 { 92 .name = "1024x768-75", 93 .refresh = 75, 94 .xres = 1024, 95 .yres = 768, 96 .pixclock = 15009, 97 .left_margin = 3, 98 .right_margin = 3, 99 .upper_margin = 2, 100 .lower_margin = 2, 101 .hsync_len = 80, 102 .vsync_len = 32, 103 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 104 .vmode = FB_VMODE_NONINTERLACED 105 }, 106 { 107 .name = "1280x1024-60", 108 .refresh = 60, 109 .xres = 1280, 110 .yres = 1024, 111 .pixclock = 9375, 112 .left_margin = 38, 113 .right_margin = 128, 114 .upper_margin = 2, 115 .lower_margin = 7, 116 .hsync_len = 216, 117 .vsync_len = 37, 118 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 119 .vmode = FB_VMODE_NONINTERLACED 120 }, 121 { 122 .name = "1280x1024-70", 123 .refresh = 70, 124 .xres = 1280, 125 .yres = 1024, 126 .pixclock = 9380, 127 .left_margin = 6, 128 .right_margin = 6, 129 .upper_margin = 4, 130 .lower_margin = 4, 131 .hsync_len = 60, 132 .vsync_len = 94, 133 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 134 .vmode = FB_VMODE_NONINTERLACED 135 }, 136 { 137 .name = "1280x1024-75", 138 .refresh = 75, 139 .xres = 1280, 140 .yres = 1024, 141 .pixclock = 9380, 142 .left_margin = 6, 143 .right_margin = 6, 144 .upper_margin = 4, 145 .lower_margin = 4, 146 .hsync_len = 60, 147 .vsync_len = 15, 148 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 149 .vmode = FB_VMODE_NONINTERLACED 150 }, 151 { 152 .name = "320x240", /* for AOI only */ 153 .refresh = 60, 154 .xres = 320, 155 .yres = 240, 156 .pixclock = 15385, 157 .left_margin = 0, 158 .right_margin = 0, 159 .upper_margin = 0, 160 .lower_margin = 0, 161 .hsync_len = 0, 162 .vsync_len = 0, 163 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 164 .vmode = FB_VMODE_NONINTERLACED 165 }, 166 { 167 .name = "1280x480-60", 168 .refresh = 60, 169 .xres = 1280, 170 .yres = 480, 171 .pixclock = 18939, 172 .left_margin = 353, 173 .right_margin = 47, 174 .upper_margin = 39, 175 .lower_margin = 4, 176 .hsync_len = 8, 177 .vsync_len = 2, 178 .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 179 .vmode = FB_VMODE_NONINTERLACED 180 }, 181}; 182 183static char *fb_mode = "1024x768-32@60"; 184static unsigned long default_bpp = 32; 185static int monitor_port; 186 187#if defined(CONFIG_NOT_COHERENT_CACHE) 188static u8 *coherence_data; 189static size_t coherence_data_size; 190static unsigned int d_cache_line_size; 191#endif 192 193static DEFINE_SPINLOCK(diu_lock); 194 195struct fsl_diu_data { 196 struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; 197 /*FSL_AOI_NUM has one dummy AOI */ 198 struct device_attribute dev_attr; 199 struct diu_ad *dummy_ad; 200 void *dummy_aoi_virt; 201 unsigned int irq; 202 int fb_enabled; 203 int monitor_port; 204}; 205 206struct mfb_info { 207 int index; 208 int type; 209 char *id; 210 int registered; 211 int blank; 212 unsigned long pseudo_palette[16]; 213 struct diu_ad *ad; 214 int cursor_reset; 215 unsigned char g_alpha; 216 unsigned int count; 217 int x_aoi_d; /* aoi display x offset to physical screen */ 218 int y_aoi_d; /* aoi display y offset to physical screen */ 219 struct fsl_diu_data *parent; 220}; 221 222 223static struct mfb_info mfb_template[] = { 224 { /* AOI 0 for plane 0 */ 225 .index = 0, 226 .type = MFB_TYPE_OUTPUT, 227 .id = "Panel0", 228 .registered = 0, 229 .count = 0, 230 .x_aoi_d = 0, 231 .y_aoi_d = 0, 232 }, 233 { /* AOI 0 for plane 1 */ 234 .index = 1, 235 .type = MFB_TYPE_OUTPUT, 236 .id = "Panel1 AOI0", 237 .registered = 0, 238 .g_alpha = 0xff, 239 .count = 0, 240 .x_aoi_d = 0, 241 .y_aoi_d = 0, 242 }, 243 { /* AOI 1 for plane 1 */ 244 .index = 2, 245 .type = MFB_TYPE_OUTPUT, 246 .id = "Panel1 AOI1", 247 .registered = 0, 248 .g_alpha = 0xff, 249 .count = 0, 250 .x_aoi_d = 0, 251 .y_aoi_d = 480, 252 }, 253 { /* AOI 0 for plane 2 */ 254 .index = 3, 255 .type = MFB_TYPE_OUTPUT, 256 .id = "Panel2 AOI0", 257 .registered = 0, 258 .g_alpha = 0xff, 259 .count = 0, 260 .x_aoi_d = 640, 261 .y_aoi_d = 0, 262 }, 263 { /* AOI 1 for plane 2 */ 264 .index = 4, 265 .type = MFB_TYPE_OUTPUT, 266 .id = "Panel2 AOI1", 267 .registered = 0, 268 .g_alpha = 0xff, 269 .count = 0, 270 .x_aoi_d = 640, 271 .y_aoi_d = 480, 272 }, 273}; 274 275static struct diu_hw dr = { 276 .mode = MFB_MODE1, 277 .reg_lock = __SPIN_LOCK_UNLOCKED(diu_hw.reg_lock), 278}; 279 280static struct diu_pool pool; 281 282/** 283 * fsl_diu_alloc - allocate memory for the DIU 284 * @size: number of bytes to allocate 285 * @param: returned physical address of memory 286 * 287 * This function allocates a physically-contiguous block of memory. 288 */ 289static void *fsl_diu_alloc(size_t size, phys_addr_t *phys) 290{ 291 void *virt; 292 293 pr_debug("size=%zu\n", size); 294 295 virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO); 296 if (virt) { 297 *phys = virt_to_phys(virt); 298 pr_debug("virt=%p phys=%llx\n", virt, 299 (unsigned long long)*phys); 300 } 301 302 return virt; 303} 304 305/** 306 * fsl_diu_free - release DIU memory 307 * @virt: pointer returned by fsl_diu_alloc() 308 * @size: number of bytes allocated by fsl_diu_alloc() 309 * 310 * This function releases memory allocated by fsl_diu_alloc(). 311 */ 312static void fsl_diu_free(void *virt, size_t size) 313{ 314 pr_debug("virt=%p size=%zu\n", virt, size); 315 316 if (virt && size) 317 free_pages_exact(virt, size); 318} 319 320static int fsl_diu_enable_panel(struct fb_info *info) 321{ 322 struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; 323 struct diu *hw = dr.diu_reg; 324 struct diu_ad *ad = mfbi->ad; 325 struct fsl_diu_data *machine_data = mfbi->parent; 326 int res = 0; 327 328 pr_debug("enable_panel index %d\n", mfbi->index); 329 if (mfbi->type != MFB_TYPE_OFF) { 330 switch (mfbi->index) { 331 case 0: /* plane 0 */ 332 if (hw->desc[0] != ad->paddr) 333 out_be32(&hw->desc[0], ad->paddr); 334 break; 335 case 1: /* plane 1 AOI 0 */ 336 cmfbi = machine_data->fsl_diu_info[2]->par; 337 if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ 338 if (cmfbi->count > 0) /* AOI1 open */ 339 ad->next_ad = 340 cpu_to_le32(cmfbi->ad->paddr); 341 else 342 ad->next_ad = 0; 343 out_be32(&hw->desc[1], ad->paddr); 344 } 345 break; 346 case 3: /* plane 2 AOI 0 */ 347 cmfbi = machine_data->fsl_diu_info[4]->par; 348 if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ 349 if (cmfbi->count > 0) /* AOI1 open */ 350 ad->next_ad = 351 cpu_to_le32(cmfbi->ad->paddr); 352 else 353 ad->next_ad = 0; 354 out_be32(&hw->desc[2], ad->paddr); 355 } 356 break; 357 case 2: /* plane 1 AOI 1 */ 358 pmfbi = machine_data->fsl_diu_info[1]->par; 359 ad->next_ad = 0; 360 if (hw->desc[1] == machine_data->dummy_ad->paddr) 361 out_be32(&hw->desc[1], ad->paddr); 362 else /* AOI0 open */ 363 pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); 364 break; 365 case 4: /* plane 2 AOI 1 */ 366 pmfbi = machine_data->fsl_diu_info[3]->par; 367 ad->next_ad = 0; 368 if (hw->desc[2] == machine_data->dummy_ad->paddr) 369 out_be32(&hw->desc[2], ad->paddr); 370 else /* AOI0 was open */ 371 pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); 372 break; 373 default: 374 res = -EINVAL; 375 break; 376 } 377 } else 378 res = -EINVAL; 379 return res; 380} 381 382static int fsl_diu_disable_panel(struct fb_info *info) 383{ 384 struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; 385 struct diu *hw = dr.diu_reg; 386 struct diu_ad *ad = mfbi->ad; 387 struct fsl_diu_data *machine_data = mfbi->parent; 388 int res = 0; 389 390 switch (mfbi->index) { 391 case 0: /* plane 0 */ 392 if (hw->desc[0] != machine_data->dummy_ad->paddr) 393 out_be32(&hw->desc[0], 394 machine_data->dummy_ad->paddr); 395 break; 396 case 1: /* plane 1 AOI 0 */ 397 cmfbi = machine_data->fsl_diu_info[2]->par; 398 if (cmfbi->count > 0) /* AOI1 is open */ 399 out_be32(&hw->desc[1], cmfbi->ad->paddr); 400 /* move AOI1 to the first */ 401 else /* AOI1 was closed */ 402 out_be32(&hw->desc[1], 403 machine_data->dummy_ad->paddr); 404 /* close AOI 0 */ 405 break; 406 case 3: /* plane 2 AOI 0 */ 407 cmfbi = machine_data->fsl_diu_info[4]->par; 408 if (cmfbi->count > 0) /* AOI1 is open */ 409 out_be32(&hw->desc[2], cmfbi->ad->paddr); 410 /* move AOI1 to the first */ 411 else /* AOI1 was closed */ 412 out_be32(&hw->desc[2], 413 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 out_be32(&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 out_be32(&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 754 pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual); 755 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 756 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 757 758 info->fix.smem_len = info->fix.line_length * info->var.yres_virtual; 759 pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len); 760 info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys); 761 if (info->screen_base == NULL) { 762 printk(KERN_ERR "Unable to allocate fb memory\n"); 763 return -ENOMEM; 764 } 765 info->fix.smem_start = (unsigned long) phys; 766 info->screen_size = info->fix.smem_len; 767 768 pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n", 769 info->fix.smem_start, 770 info->fix.smem_len); 771 pr_debug("screen base %p\n", info->screen_base); 772 773 return 0; 774} 775 776static void unmap_video_memory(struct fb_info *info) 777{ 778 fsl_diu_free(info->screen_base, info->fix.smem_len); 779 info->screen_base = NULL; 780 info->fix.smem_start = 0; 781 info->fix.smem_len = 0; 782} 783 784/* 785 * Using the fb_var_screeninfo in fb_info we set the aoi of this 786 * particular framebuffer. It is a light version of fsl_diu_set_par. 787 */ 788static int fsl_diu_set_aoi(struct fb_info *info) 789{ 790 struct fb_var_screeninfo *var = &info->var; 791 struct mfb_info *mfbi = info->par; 792 struct diu_ad *ad = mfbi->ad; 793 794 /* AOI should not be greater than display size */ 795 ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); 796 ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); 797 return 0; 798} 799 800/* 801 * Using the fb_var_screeninfo in fb_info we set the resolution of this 802 * particular framebuffer. This function alters the fb_fix_screeninfo stored 803 * in fb_info. It does not alter var in fb_info since we are using that 804 * data. This means we depend on the data in var inside fb_info to be 805 * supported by the hardware. fsl_diu_check_var is always called before 806 * fsl_diu_set_par to ensure this. 807 */ 808static int fsl_diu_set_par(struct fb_info *info) 809{ 810 unsigned long len; 811 struct fb_var_screeninfo *var = &info->var; 812 struct mfb_info *mfbi = info->par; 813 struct fsl_diu_data *machine_data = mfbi->parent; 814 struct diu_ad *ad = mfbi->ad; 815 struct diu *hw; 816 817 hw = dr.diu_reg; 818 819 set_fix(info); 820 mfbi->cursor_reset = 1; 821 822 len = info->var.yres_virtual * info->fix.line_length; 823 /* Alloc & dealloc each time resolution/bpp change */ 824 if (len != info->fix.smem_len) { 825 if (info->fix.smem_start) 826 unmap_video_memory(info); 827 pr_debug("SET PAR: smem_len = %d\n", info->fix.smem_len); 828 829 /* Memory allocation for framebuffer */ 830 if (map_video_memory(info)) { 831 printk(KERN_ERR "Unable to allocate fb memory 1\n"); 832 return -ENOMEM; 833 } 834 } 835 836 ad->pix_fmt = 837 diu_ops.get_pixel_format(var->bits_per_pixel, 838 machine_data->monitor_port); 839 ad->addr = cpu_to_le32(info->fix.smem_start); 840 ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | 841 var->xres_virtual) | mfbi->g_alpha; 842 /* AOI should not be greater than display size */ 843 ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); 844 ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); 845 ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); 846 847 /* Disable chroma keying function */ 848 ad->ckmax_r = 0; 849 ad->ckmax_g = 0; 850 ad->ckmax_b = 0; 851 852 ad->ckmin_r = 255; 853 ad->ckmin_g = 255; 854 ad->ckmin_b = 255; 855 856 if (mfbi->index == 0) 857 update_lcdc(info); 858 return 0; 859} 860 861static inline __u32 CNVT_TOHW(__u32 val, __u32 width) 862{ 863 return ((val<<width) + 0x7FFF - val)>>16; 864} 865 866/* 867 * Set a single color register. The values supplied have a 16 bit magnitude 868 * which needs to be scaled in this function for the hardware. Things to take 869 * into consideration are how many color registers, if any, are supported with 870 * the current color visual. With truecolor mode no color palettes are 871 * supported. Here a psuedo palette is created which we store the value in 872 * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited 873 * color palette. 874 */ 875static int fsl_diu_setcolreg(unsigned regno, unsigned red, unsigned green, 876 unsigned blue, unsigned transp, struct fb_info *info) 877{ 878 int ret = 1; 879 880 /* 881 * If greyscale is true, then we convert the RGB value 882 * to greyscale no matter what visual we are using. 883 */ 884 if (info->var.grayscale) 885 red = green = blue = (19595 * red + 38470 * green + 886 7471 * blue) >> 16; 887 switch (info->fix.visual) { 888 case FB_VISUAL_TRUECOLOR: 889 /* 890 * 16-bit True Colour. We encode the RGB value 891 * according to the RGB bitfield information. 892 */ 893 if (regno < 16) { 894 u32 *pal = info->pseudo_palette; 895 u32 v; 896 897 red = CNVT_TOHW(red, info->var.red.length); 898 green = CNVT_TOHW(green, info->var.green.length); 899 blue = CNVT_TOHW(blue, info->var.blue.length); 900 transp = CNVT_TOHW(transp, info->var.transp.length); 901 902 v = (red << info->var.red.offset) | 903 (green << info->var.green.offset) | 904 (blue << info->var.blue.offset) | 905 (transp << info->var.transp.offset); 906 907 pal[regno] = v; 908 ret = 0; 909 } 910 break; 911 case FB_VISUAL_STATIC_PSEUDOCOLOR: 912 case FB_VISUAL_PSEUDOCOLOR: 913 break; 914 } 915 916 return ret; 917} 918 919/* 920 * Pan (or wrap, depending on the `vmode' field) the display using the 921 * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values 922 * don't fit, return -EINVAL. 923 */ 924static int fsl_diu_pan_display(struct fb_var_screeninfo *var, 925 struct fb_info *info) 926{ 927 if ((info->var.xoffset == var->xoffset) && 928 (info->var.yoffset == var->yoffset)) 929 return 0; /* No change, do nothing */ 930 931 if (var->xoffset < 0 || var->yoffset < 0 932 || var->xoffset + info->var.xres > info->var.xres_virtual 933 || var->yoffset + info->var.yres > info->var.yres_virtual) 934 return -EINVAL; 935 936 info->var.xoffset = var->xoffset; 937 info->var.yoffset = var->yoffset; 938 939 if (var->vmode & FB_VMODE_YWRAP) 940 info->var.vmode |= FB_VMODE_YWRAP; 941 else 942 info->var.vmode &= ~FB_VMODE_YWRAP; 943 944 fsl_diu_set_aoi(info); 945 946 return 0; 947} 948 949/* 950 * Blank the screen if blank_mode != 0, else unblank. Return 0 if blanking 951 * succeeded, != 0 if un-/blanking failed. 952 * blank_mode == 2: suspend vsync 953 * blank_mode == 3: suspend hsync 954 * blank_mode == 4: powerdown 955 */ 956static int fsl_diu_blank(int blank_mode, struct fb_info *info) 957{ 958 struct mfb_info *mfbi = info->par; 959 960 mfbi->blank = blank_mode; 961 962 switch (blank_mode) { 963 case FB_BLANK_VSYNC_SUSPEND: 964 case FB_BLANK_HSYNC_SUSPEND: 965 /* FIXME: fixes to enable_panel and enable lcdc needed */ 966 case FB_BLANK_NORMAL: 967 /* fsl_diu_disable_panel(info);*/ 968 break; 969 case FB_BLANK_POWERDOWN: 970 /* disable_lcdc(info); */ 971 break; 972 case FB_BLANK_UNBLANK: 973 /* fsl_diu_enable_panel(info);*/ 974 break; 975 } 976 977 return 0; 978} 979 980static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, 981 unsigned long arg) 982{ 983 struct mfb_info *mfbi = info->par; 984 struct diu_ad *ad = mfbi->ad; 985 struct mfb_chroma_key ck; 986 unsigned char global_alpha; 987 struct aoi_display_offset aoi_d; 988 __u32 pix_fmt; 989 void __user *buf = (void __user *)arg; 990 991 if (!arg) 992 return -EINVAL; 993 switch (cmd) { 994 case MFB_SET_PIXFMT: 995 if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) 996 return -EFAULT; 997 ad->pix_fmt = pix_fmt; 998 pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); 999 break; 1000 case MFB_GET_PIXFMT: 1001 pix_fmt = ad->pix_fmt; 1002 if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) 1003 return -EFAULT; 1004 pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); 1005 break; 1006 case MFB_SET_AOID: 1007 if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) 1008 return -EFAULT; 1009 mfbi->x_aoi_d = aoi_d.x_aoi_d; 1010 mfbi->y_aoi_d = aoi_d.y_aoi_d; 1011 pr_debug("set AOI display offset of index %d to (%d,%d)\n", 1012 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1013 fsl_diu_check_var(&info->var, info); 1014 fsl_diu_set_aoi(info); 1015 break; 1016 case MFB_GET_AOID: 1017 aoi_d.x_aoi_d = mfbi->x_aoi_d; 1018 aoi_d.y_aoi_d = mfbi->y_aoi_d; 1019 if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) 1020 return -EFAULT; 1021 pr_debug("get AOI display offset of index %d (%d,%d)\n", 1022 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1023 break; 1024 case MFB_GET_ALPHA: 1025 global_alpha = mfbi->g_alpha; 1026 if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) 1027 return -EFAULT; 1028 pr_debug("get global alpha of index %d\n", mfbi->index); 1029 break; 1030 case MFB_SET_ALPHA: 1031 /* set panel information */ 1032 if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) 1033 return -EFAULT; 1034 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | 1035 (global_alpha & 0xff); 1036 mfbi->g_alpha = global_alpha; 1037 pr_debug("set global alpha for index %d\n", mfbi->index); 1038 break; 1039 case MFB_SET_CHROMA_KEY: 1040 /* set panel winformation */ 1041 if (copy_from_user(&ck, buf, sizeof(ck))) 1042 return -EFAULT; 1043 1044 if (ck.enable && 1045 (ck.red_max < ck.red_min || 1046 ck.green_max < ck.green_min || 1047 ck.blue_max < ck.blue_min)) 1048 return -EINVAL; 1049 1050 if (!ck.enable) { 1051 ad->ckmax_r = 0; 1052 ad->ckmax_g = 0; 1053 ad->ckmax_b = 0; 1054 ad->ckmin_r = 255; 1055 ad->ckmin_g = 255; 1056 ad->ckmin_b = 255; 1057 } else { 1058 ad->ckmax_r = ck.red_max; 1059 ad->ckmax_g = ck.green_max; 1060 ad->ckmax_b = ck.blue_max; 1061 ad->ckmin_r = ck.red_min; 1062 ad->ckmin_g = ck.green_min; 1063 ad->ckmin_b = ck.blue_min; 1064 } 1065 pr_debug("set chroma key\n"); 1066 break; 1067 case FBIOGET_GWINFO: 1068 if (mfbi->type == MFB_TYPE_OFF) 1069 return -ENODEV; 1070 /* get graphic window information */ 1071 if (copy_to_user(buf, ad, sizeof(*ad))) 1072 return -EFAULT; 1073 break; 1074 case FBIOGET_HWCINFO: 1075 pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); 1076 break; 1077 case FBIOPUT_MODEINFO: 1078 pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); 1079 break; 1080 case FBIOGET_DISPINFO: 1081 pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); 1082 break; 1083 1084 default: 1085 printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); 1086 return -ENOIOCTLCMD; 1087 } 1088 1089 return 0; 1090} 1091 1092/* turn on fb if count == 1 1093 */ 1094static int fsl_diu_open(struct fb_info *info, int user) 1095{ 1096 struct mfb_info *mfbi = info->par; 1097 int res = 0; 1098 1099 spin_lock(&diu_lock); 1100 mfbi->count++; 1101 if (mfbi->count == 1) { 1102 pr_debug("open plane index %d\n", mfbi->index); 1103 fsl_diu_check_var(&info->var, info); 1104 res = fsl_diu_set_par(info); 1105 if (res < 0) 1106 mfbi->count--; 1107 else { 1108 res = fsl_diu_enable_panel(info); 1109 if (res < 0) 1110 mfbi->count--; 1111 } 1112 } 1113 1114 spin_unlock(&diu_lock); 1115 return res; 1116} 1117 1118/* turn off fb if count == 0 1119 */ 1120static int fsl_diu_release(struct fb_info *info, int user) 1121{ 1122 struct mfb_info *mfbi = info->par; 1123 int res = 0; 1124 1125 spin_lock(&diu_lock); 1126 mfbi->count--; 1127 if (mfbi->count == 0) { 1128 pr_debug("release plane index %d\n", mfbi->index); 1129 res = fsl_diu_disable_panel(info); 1130 if (res < 0) 1131 mfbi->count++; 1132 } 1133 spin_unlock(&diu_lock); 1134 return res; 1135} 1136 1137static struct fb_ops fsl_diu_ops = { 1138 .owner = THIS_MODULE, 1139 .fb_check_var = fsl_diu_check_var, 1140 .fb_set_par = fsl_diu_set_par, 1141 .fb_setcolreg = fsl_diu_setcolreg, 1142 .fb_blank = fsl_diu_blank, 1143 .fb_pan_display = fsl_diu_pan_display, 1144 .fb_fillrect = cfb_fillrect, 1145 .fb_copyarea = cfb_copyarea, 1146 .fb_imageblit = cfb_imageblit, 1147 .fb_ioctl = fsl_diu_ioctl, 1148 .fb_open = fsl_diu_open, 1149 .fb_release = fsl_diu_release, 1150}; 1151 1152static int init_fbinfo(struct fb_info *info) 1153{ 1154 struct mfb_info *mfbi = info->par; 1155 1156 info->device = NULL; 1157 info->var.activate = FB_ACTIVATE_NOW; 1158 info->fbops = &fsl_diu_ops; 1159 info->flags = FBINFO_FLAG_DEFAULT; 1160 info->pseudo_palette = &mfbi->pseudo_palette; 1161 1162 /* Allocate colormap */ 1163 fb_alloc_cmap(&info->cmap, 16, 0); 1164 return 0; 1165} 1166 1167static int __devinit install_fb(struct fb_info *info) 1168{ 1169 int rc; 1170 struct mfb_info *mfbi = info->par; 1171 const char *aoi_mode, *init_aoi_mode = "320x240"; 1172 1173 if (init_fbinfo(info)) 1174 return -EINVAL; 1175 1176 if (mfbi->index == 0) /* plane 0 */ 1177 aoi_mode = fb_mode; 1178 else 1179 aoi_mode = init_aoi_mode; 1180 pr_debug("mode used = %s\n", aoi_mode); 1181 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, 1182 ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); 1183 1184 switch (rc) { 1185 case 1: 1186 pr_debug("using mode specified in @mode\n"); 1187 break; 1188 case 2: 1189 pr_debug("using mode specified in @mode " 1190 "with ignored refresh rate\n"); 1191 break; 1192 case 3: 1193 pr_debug("using mode default mode\n"); 1194 break; 1195 case 4: 1196 pr_debug("using mode from list\n"); 1197 break; 1198 default: 1199 pr_debug("rc = %d\n", rc); 1200 pr_debug("failed to find mode\n"); 1201 return -EINVAL; 1202 break; 1203 } 1204 1205 pr_debug("xres_virtual %d\n", info->var.xres_virtual); 1206 pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); 1207 1208 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 1209 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 1210 1211 if (mfbi->type == MFB_TYPE_OFF) 1212 mfbi->blank = FB_BLANK_NORMAL; 1213 else 1214 mfbi->blank = FB_BLANK_UNBLANK; 1215 1216 if (fsl_diu_check_var(&info->var, info)) { 1217 printk(KERN_ERR "fb_check_var failed"); 1218 fb_dealloc_cmap(&info->cmap); 1219 return -EINVAL; 1220 } 1221 1222 if (fsl_diu_set_par(info)) { 1223 printk(KERN_ERR "fb_set_par failed"); 1224 fb_dealloc_cmap(&info->cmap); 1225 return -EINVAL; 1226 } 1227 1228 if (register_framebuffer(info) < 0) { 1229 printk(KERN_ERR "register_framebuffer failed"); 1230 unmap_video_memory(info); 1231 fb_dealloc_cmap(&info->cmap); 1232 return -EINVAL; 1233 } 1234 1235 mfbi->registered = 1; 1236 printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", 1237 info->node, info->fix.id); 1238 1239 return 0; 1240} 1241 1242static void uninstall_fb(struct fb_info *info) 1243{ 1244 struct mfb_info *mfbi = info->par; 1245 1246 if (!mfbi->registered) 1247 return; 1248 1249 unregister_framebuffer(info); 1250 unmap_video_memory(info); 1251 if (&info->cmap) 1252 fb_dealloc_cmap(&info->cmap); 1253 1254 mfbi->registered = 0; 1255} 1256 1257static irqreturn_t fsl_diu_isr(int irq, void *dev_id) 1258{ 1259 struct diu *hw = dr.diu_reg; 1260 unsigned int status = in_be32(&hw->int_status); 1261 1262 if (status) { 1263 /* This is the workaround for underrun */ 1264 if (status & INT_UNDRUN) { 1265 out_be32(&hw->diu_mode, 0); 1266 pr_debug("Err: DIU occurs underrun!\n"); 1267 udelay(1); 1268 out_be32(&hw->diu_mode, 1); 1269 } 1270#if defined(CONFIG_NOT_COHERENT_CACHE) 1271 else if (status & INT_VSYNC) { 1272 unsigned int i; 1273 for (i = 0; i < coherence_data_size; 1274 i += d_cache_line_size) 1275 __asm__ __volatile__ ( 1276 "dcbz 0, %[input]" 1277 ::[input]"r"(&coherence_data[i])); 1278 } 1279#endif 1280 return IRQ_HANDLED; 1281 } 1282 return IRQ_NONE; 1283} 1284 1285static int request_irq_local(int irq) 1286{ 1287 unsigned long status, ints; 1288 struct diu *hw; 1289 int ret; 1290 1291 hw = dr.diu_reg; 1292 1293 /* Read to clear the status */ 1294 status = in_be32(&hw->int_status); 1295 1296 ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL); 1297 if (ret) 1298 pr_info("Request diu IRQ failed.\n"); 1299 else { 1300 ints = INT_PARERR | INT_LS_BF_VS; 1301#if !defined(CONFIG_NOT_COHERENT_CACHE) 1302 ints |= INT_VSYNC; 1303#endif 1304 if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) 1305 ints |= INT_VSYNC_WB; 1306 1307 /* Read to clear the status */ 1308 status = in_be32(&hw->int_status); 1309 out_be32(&hw->int_mask, ints); 1310 } 1311 return ret; 1312} 1313 1314static void free_irq_local(int irq) 1315{ 1316 struct diu *hw = dr.diu_reg; 1317 1318 /* Disable all LCDC interrupt */ 1319 out_be32(&hw->int_mask, 0x1f); 1320 1321 free_irq(irq, NULL); 1322} 1323 1324#ifdef CONFIG_PM 1325/* 1326 * Power management hooks. Note that we won't be called from IRQ context, 1327 * unlike the blank functions above, so we may sleep. 1328 */ 1329static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state) 1330{ 1331 struct fsl_diu_data *machine_data; 1332 1333 machine_data = dev_get_drvdata(&ofdev->dev); 1334 disable_lcdc(machine_data->fsl_diu_info[0]); 1335 1336 return 0; 1337} 1338 1339static int fsl_diu_resume(struct of_device *ofdev) 1340{ 1341 struct fsl_diu_data *machine_data; 1342 1343 machine_data = dev_get_drvdata(&ofdev->dev); 1344 enable_lcdc(machine_data->fsl_diu_info[0]); 1345 1346 return 0; 1347} 1348 1349#else 1350#define fsl_diu_suspend NULL 1351#define fsl_diu_resume NULL 1352#endif /* CONFIG_PM */ 1353 1354/* Align to 64-bit(8-byte), 32-byte, etc. */ 1355static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, 1356 u32 bytes_align) 1357{ 1358 u32 offset, ssize; 1359 u32 mask; 1360 dma_addr_t paddr = 0; 1361 1362 ssize = size + bytes_align; 1363 buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA | 1364 __GFP_ZERO); 1365 if (!buf->vaddr) 1366 return -ENOMEM; 1367 1368 buf->paddr = (__u32) paddr; 1369 1370 mask = bytes_align - 1; 1371 offset = (u32)buf->paddr & mask; 1372 if (offset) { 1373 buf->offset = bytes_align - offset; 1374 buf->paddr = (u32)buf->paddr + offset; 1375 } else 1376 buf->offset = 0; 1377 return 0; 1378} 1379 1380static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, 1381 u32 bytes_align) 1382{ 1383 dma_free_coherent(dev, size + bytes_align, 1384 buf->vaddr, (buf->paddr - buf->offset)); 1385 return; 1386} 1387 1388static ssize_t store_monitor(struct device *device, 1389 struct device_attribute *attr, const char *buf, size_t count) 1390{ 1391 int old_monitor_port; 1392 unsigned long val; 1393 struct fsl_diu_data *machine_data = 1394 container_of(attr, struct fsl_diu_data, dev_attr); 1395 1396 if (strict_strtoul(buf, 10, &val)) 1397 return 0; 1398 1399 old_monitor_port = machine_data->monitor_port; 1400 machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); 1401 1402 if (old_monitor_port != machine_data->monitor_port) { 1403 /* All AOIs need adjust pixel format 1404 * fsl_diu_set_par only change the pixsel format here 1405 * unlikely to fail. */ 1406 fsl_diu_set_par(machine_data->fsl_diu_info[0]); 1407 fsl_diu_set_par(machine_data->fsl_diu_info[1]); 1408 fsl_diu_set_par(machine_data->fsl_diu_info[2]); 1409 fsl_diu_set_par(machine_data->fsl_diu_info[3]); 1410 fsl_diu_set_par(machine_data->fsl_diu_info[4]); 1411 } 1412 return count; 1413} 1414 1415static ssize_t show_monitor(struct device *device, 1416 struct device_attribute *attr, char *buf) 1417{ 1418 struct fsl_diu_data *machine_data = 1419 container_of(attr, struct fsl_diu_data, dev_attr); 1420 return diu_ops.show_monitor_port(machine_data->monitor_port, buf); 1421} 1422 1423static int __devinit fsl_diu_probe(struct of_device *ofdev, 1424 const struct of_device_id *match) 1425{ 1426 struct device_node *np = ofdev->node; 1427 struct mfb_info *mfbi; 1428 phys_addr_t dummy_ad_addr; 1429 int ret, i, error = 0; 1430 struct resource res; 1431 struct fsl_diu_data *machine_data; 1432 1433 machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); 1434 if (!machine_data) 1435 return -ENOMEM; 1436 1437 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1438 machine_data->fsl_diu_info[i] = 1439 framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); 1440 if (!machine_data->fsl_diu_info[i]) { 1441 dev_err(&ofdev->dev, "cannot allocate memory\n"); 1442 ret = -ENOMEM; 1443 goto error2; 1444 } 1445 mfbi = machine_data->fsl_diu_info[i]->par; 1446 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); 1447 mfbi->parent = machine_data; 1448 } 1449 1450 ret = of_address_to_resource(np, 0, &res); 1451 if (ret) { 1452 dev_err(&ofdev->dev, "could not obtain DIU address\n"); 1453 goto error; 1454 } 1455 if (!res.start) { 1456 dev_err(&ofdev->dev, "invalid DIU address\n"); 1457 goto error; 1458 } 1459 dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); 1460 1461 dr.diu_reg = ioremap(res.start, sizeof(struct diu)); 1462 if (!dr.diu_reg) { 1463 dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); 1464 ret = -EFAULT; 1465 goto error2; 1466 } 1467 1468 out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ 1469 1470 /* Get the IRQ of the DIU */ 1471 machine_data->irq = irq_of_parse_and_map(np, 0); 1472 1473 if (!machine_data->irq) { 1474 dev_err(&ofdev->dev, "could not get DIU IRQ\n"); 1475 ret = -EINVAL; 1476 goto error; 1477 } 1478 machine_data->monitor_port = monitor_port; 1479 1480 /* Area descriptor memory pool aligns to 64-bit boundary */ 1481 if (allocate_buf(&ofdev->dev, &pool.ad, 1482 sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) 1483 return -ENOMEM; 1484 1485 /* Get memory for Gamma Table - 32-byte aligned memory */ 1486 if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) { 1487 ret = -ENOMEM; 1488 goto error; 1489 } 1490 1491 /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ 1492 if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1493 32)) { 1494 ret = -ENOMEM; 1495 goto error; 1496 } 1497 1498 i = ARRAY_SIZE(machine_data->fsl_diu_info); 1499 machine_data->dummy_ad = (struct diu_ad *) 1500 ((u32)pool.ad.vaddr + pool.ad.offset) + i; 1501 machine_data->dummy_ad->paddr = pool.ad.paddr + 1502 i * sizeof(struct diu_ad); 1503 machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); 1504 if (!machine_data->dummy_aoi_virt) { 1505 ret = -ENOMEM; 1506 goto error; 1507 } 1508 machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); 1509 machine_data->dummy_ad->pix_fmt = 0x88882317; 1510 machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); 1511 machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); 1512 machine_data->dummy_ad->offset_xyi = 0; 1513 machine_data->dummy_ad->offset_xyd = 0; 1514 machine_data->dummy_ad->next_ad = 0; 1515 1516 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); 1517 out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); 1518 out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); 1519 1520 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1521 machine_data->fsl_diu_info[i]->fix.smem_start = 0; 1522 mfbi = machine_data->fsl_diu_info[i]->par; 1523 mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr 1524 + pool.ad.offset) + i; 1525 mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); 1526 ret = install_fb(machine_data->fsl_diu_info[i]); 1527 if (ret) { 1528 dev_err(&ofdev->dev, 1529 "Failed to register framebuffer %d\n", 1530 i); 1531 goto error; 1532 } 1533 } 1534 1535 if (request_irq_local(machine_data->irq)) { 1536 dev_err(machine_data->fsl_diu_info[0]->dev, 1537 "could not request irq for diu."); 1538 goto error; 1539 } 1540 1541 machine_data->dev_attr.attr.name = "monitor"; 1542 machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; 1543 machine_data->dev_attr.show = show_monitor; 1544 machine_data->dev_attr.store = store_monitor; 1545 error = device_create_file(machine_data->fsl_diu_info[0]->dev, 1546 &machine_data->dev_attr); 1547 if (error) { 1548 dev_err(machine_data->fsl_diu_info[0]->dev, 1549 "could not create sysfs %s file\n", 1550 machine_data->dev_attr.attr.name); 1551 } 1552 1553 dev_set_drvdata(&ofdev->dev, machine_data); 1554 return 0; 1555 1556error: 1557 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); 1558 i > 0; i--) 1559 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1560 if (pool.ad.vaddr) 1561 free_buf(&ofdev->dev, &pool.ad, 1562 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1563 if (pool.gamma.vaddr) 1564 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1565 if (pool.cursor.vaddr) 1566 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1567 32); 1568 if (machine_data->dummy_aoi_virt) 1569 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1570 iounmap(dr.diu_reg); 1571 1572error2: 1573 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1574 if (machine_data->fsl_diu_info[i]) 1575 framebuffer_release(machine_data->fsl_diu_info[i]); 1576 kfree(machine_data); 1577 1578 return ret; 1579} 1580 1581 1582static int fsl_diu_remove(struct of_device *ofdev) 1583{ 1584 struct fsl_diu_data *machine_data; 1585 int i; 1586 1587 machine_data = dev_get_drvdata(&ofdev->dev); 1588 disable_lcdc(machine_data->fsl_diu_info[0]); 1589 free_irq_local(machine_data->irq); 1590 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) 1591 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1592 if (pool.ad.vaddr) 1593 free_buf(&ofdev->dev, &pool.ad, 1594 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1595 if (pool.gamma.vaddr) 1596 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1597 if (pool.cursor.vaddr) 1598 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1599 32); 1600 if (machine_data->dummy_aoi_virt) 1601 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1602 iounmap(dr.diu_reg); 1603 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1604 if (machine_data->fsl_diu_info[i]) 1605 framebuffer_release(machine_data->fsl_diu_info[i]); 1606 kfree(machine_data); 1607 1608 return 0; 1609} 1610 1611#ifndef MODULE 1612static int __init fsl_diu_setup(char *options) 1613{ 1614 char *opt; 1615 unsigned long val; 1616 1617 if (!options || !*options) 1618 return 0; 1619 1620 while ((opt = strsep(&options, ",")) != NULL) { 1621 if (!*opt) 1622 continue; 1623 if (!strncmp(opt, "monitor=", 8)) { 1624 if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) 1625 monitor_port = val; 1626 } else if (!strncmp(opt, "bpp=", 4)) { 1627 if (!strict_strtoul(opt + 4, 10, &val)) 1628 default_bpp = val; 1629 } else 1630 fb_mode = opt; 1631 } 1632 1633 return 0; 1634} 1635#endif 1636 1637static struct of_device_id fsl_diu_match[] = { 1638 { 1639 .compatible = "fsl,diu", 1640 }, 1641 {} 1642}; 1643MODULE_DEVICE_TABLE(of, fsl_diu_match); 1644 1645static struct of_platform_driver fsl_diu_driver = { 1646 .owner = THIS_MODULE, 1647 .name = "fsl_diu", 1648 .match_table = fsl_diu_match, 1649 .probe = fsl_diu_probe, 1650 .remove = fsl_diu_remove, 1651 .suspend = fsl_diu_suspend, 1652 .resume = fsl_diu_resume, 1653}; 1654 1655static int __init fsl_diu_init(void) 1656{ 1657#ifdef CONFIG_NOT_COHERENT_CACHE 1658 struct device_node *np; 1659 const u32 *prop; 1660#endif 1661 int ret; 1662#ifndef MODULE 1663 char *option; 1664 1665 /* 1666 * For kernel boot options (in 'video=xxxfb:<options>' format) 1667 */ 1668 if (fb_get_options("fslfb", &option)) 1669 return -ENODEV; 1670 fsl_diu_setup(option); 1671#endif 1672 printk(KERN_INFO "Freescale DIU driver\n"); 1673 1674#ifdef CONFIG_NOT_COHERENT_CACHE 1675 np = of_find_node_by_type(NULL, "cpu"); 1676 if (!np) { 1677 printk(KERN_ERR "Err: can't find device node 'cpu'\n"); 1678 return -ENODEV; 1679 } 1680 1681 prop = of_get_property(np, "d-cache-size", NULL); 1682 if (prop == NULL) { 1683 of_node_put(np); 1684 return -ENODEV; 1685 } 1686 1687 /* Freescale PLRU requires 13/8 times the cache size to do a proper 1688 displacement flush 1689 */ 1690 coherence_data_size = *prop * 13; 1691 coherence_data_size /= 8; 1692 1693 prop = of_get_property(np, "d-cache-line-size", NULL); 1694 if (prop == NULL) { 1695 of_node_put(np); 1696 return -ENODEV; 1697 } 1698 d_cache_line_size = *prop; 1699 1700 of_node_put(np); 1701 coherence_data = vmalloc(coherence_data_size); 1702 if (!coherence_data) 1703 return -ENOMEM; 1704#endif 1705 ret = of_register_platform_driver(&fsl_diu_driver); 1706 if (ret) { 1707 printk(KERN_ERR 1708 "fsl-diu: failed to register platform driver\n"); 1709#if defined(CONFIG_NOT_COHERENT_CACHE) 1710 vfree(coherence_data); 1711#endif 1712 iounmap(dr.diu_reg); 1713 } 1714 return ret; 1715} 1716 1717static void __exit fsl_diu_exit(void) 1718{ 1719 of_unregister_platform_driver(&fsl_diu_driver); 1720#if defined(CONFIG_NOT_COHERENT_CACHE) 1721 vfree(coherence_data); 1722#endif 1723} 1724 1725module_init(fsl_diu_init); 1726module_exit(fsl_diu_exit); 1727 1728MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); 1729MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); 1730MODULE_LICENSE("GPL"); 1731 1732module_param_named(mode, fb_mode, charp, 0); 1733MODULE_PARM_DESC(mode, 1734 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 1735module_param_named(bpp, default_bpp, ulong, 0); 1736MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); 1737module_param_named(monitor, monitor_port, int, 0); 1738MODULE_PARM_DESC(monitor, 1739 "Specify the monitor port (0, 1 or 2) if supported by the platform"); 1740