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.34-rc3 1743 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 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 /* FIXME: fixes to enable_panel and enable lcdc needed */ 970 case FB_BLANK_NORMAL: 971 /* fsl_diu_disable_panel(info);*/ 972 break; 973 case FB_BLANK_POWERDOWN: 974 /* disable_lcdc(info); */ 975 break; 976 case FB_BLANK_UNBLANK: 977 /* fsl_diu_enable_panel(info);*/ 978 break; 979 } 980 981 return 0; 982} 983 984static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, 985 unsigned long arg) 986{ 987 struct mfb_info *mfbi = info->par; 988 struct diu_ad *ad = mfbi->ad; 989 struct mfb_chroma_key ck; 990 unsigned char global_alpha; 991 struct aoi_display_offset aoi_d; 992 __u32 pix_fmt; 993 void __user *buf = (void __user *)arg; 994 995 if (!arg) 996 return -EINVAL; 997 switch (cmd) { 998 case MFB_SET_PIXFMT: 999 if (copy_from_user(&pix_fmt, buf, sizeof(pix_fmt))) 1000 return -EFAULT; 1001 ad->pix_fmt = pix_fmt; 1002 pr_debug("Set pixel format to 0x%08x\n", ad->pix_fmt); 1003 break; 1004 case MFB_GET_PIXFMT: 1005 pix_fmt = ad->pix_fmt; 1006 if (copy_to_user(buf, &pix_fmt, sizeof(pix_fmt))) 1007 return -EFAULT; 1008 pr_debug("get pixel format 0x%08x\n", ad->pix_fmt); 1009 break; 1010 case MFB_SET_AOID: 1011 if (copy_from_user(&aoi_d, buf, sizeof(aoi_d))) 1012 return -EFAULT; 1013 mfbi->x_aoi_d = aoi_d.x_aoi_d; 1014 mfbi->y_aoi_d = aoi_d.y_aoi_d; 1015 pr_debug("set AOI display offset of index %d to (%d,%d)\n", 1016 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1017 fsl_diu_check_var(&info->var, info); 1018 fsl_diu_set_aoi(info); 1019 break; 1020 case MFB_GET_AOID: 1021 aoi_d.x_aoi_d = mfbi->x_aoi_d; 1022 aoi_d.y_aoi_d = mfbi->y_aoi_d; 1023 if (copy_to_user(buf, &aoi_d, sizeof(aoi_d))) 1024 return -EFAULT; 1025 pr_debug("get AOI display offset of index %d (%d,%d)\n", 1026 mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); 1027 break; 1028 case MFB_GET_ALPHA: 1029 global_alpha = mfbi->g_alpha; 1030 if (copy_to_user(buf, &global_alpha, sizeof(global_alpha))) 1031 return -EFAULT; 1032 pr_debug("get global alpha of index %d\n", mfbi->index); 1033 break; 1034 case MFB_SET_ALPHA: 1035 /* set panel information */ 1036 if (copy_from_user(&global_alpha, buf, sizeof(global_alpha))) 1037 return -EFAULT; 1038 ad->src_size_g_alpha = (ad->src_size_g_alpha & (~0xff)) | 1039 (global_alpha & 0xff); 1040 mfbi->g_alpha = global_alpha; 1041 pr_debug("set global alpha for index %d\n", mfbi->index); 1042 break; 1043 case MFB_SET_CHROMA_KEY: 1044 /* set panel winformation */ 1045 if (copy_from_user(&ck, buf, sizeof(ck))) 1046 return -EFAULT; 1047 1048 if (ck.enable && 1049 (ck.red_max < ck.red_min || 1050 ck.green_max < ck.green_min || 1051 ck.blue_max < ck.blue_min)) 1052 return -EINVAL; 1053 1054 if (!ck.enable) { 1055 ad->ckmax_r = 0; 1056 ad->ckmax_g = 0; 1057 ad->ckmax_b = 0; 1058 ad->ckmin_r = 255; 1059 ad->ckmin_g = 255; 1060 ad->ckmin_b = 255; 1061 } else { 1062 ad->ckmax_r = ck.red_max; 1063 ad->ckmax_g = ck.green_max; 1064 ad->ckmax_b = ck.blue_max; 1065 ad->ckmin_r = ck.red_min; 1066 ad->ckmin_g = ck.green_min; 1067 ad->ckmin_b = ck.blue_min; 1068 } 1069 pr_debug("set chroma key\n"); 1070 break; 1071 case FBIOGET_GWINFO: 1072 if (mfbi->type == MFB_TYPE_OFF) 1073 return -ENODEV; 1074 /* get graphic window information */ 1075 if (copy_to_user(buf, ad, sizeof(*ad))) 1076 return -EFAULT; 1077 break; 1078 case FBIOGET_HWCINFO: 1079 pr_debug("FBIOGET_HWCINFO:0x%08x\n", FBIOGET_HWCINFO); 1080 break; 1081 case FBIOPUT_MODEINFO: 1082 pr_debug("FBIOPUT_MODEINFO:0x%08x\n", FBIOPUT_MODEINFO); 1083 break; 1084 case FBIOGET_DISPINFO: 1085 pr_debug("FBIOGET_DISPINFO:0x%08x\n", FBIOGET_DISPINFO); 1086 break; 1087 1088 default: 1089 printk(KERN_ERR "Unknown ioctl command (0x%08X)\n", cmd); 1090 return -ENOIOCTLCMD; 1091 } 1092 1093 return 0; 1094} 1095 1096/* turn on fb if count == 1 1097 */ 1098static int fsl_diu_open(struct fb_info *info, int user) 1099{ 1100 struct mfb_info *mfbi = info->par; 1101 int res = 0; 1102 1103 spin_lock(&diu_lock); 1104 mfbi->count++; 1105 if (mfbi->count == 1) { 1106 pr_debug("open plane index %d\n", mfbi->index); 1107 fsl_diu_check_var(&info->var, info); 1108 res = fsl_diu_set_par(info); 1109 if (res < 0) 1110 mfbi->count--; 1111 else { 1112 res = fsl_diu_enable_panel(info); 1113 if (res < 0) 1114 mfbi->count--; 1115 } 1116 } 1117 1118 spin_unlock(&diu_lock); 1119 return res; 1120} 1121 1122/* turn off fb if count == 0 1123 */ 1124static int fsl_diu_release(struct fb_info *info, int user) 1125{ 1126 struct mfb_info *mfbi = info->par; 1127 int res = 0; 1128 1129 spin_lock(&diu_lock); 1130 mfbi->count--; 1131 if (mfbi->count == 0) { 1132 pr_debug("release plane index %d\n", mfbi->index); 1133 res = fsl_diu_disable_panel(info); 1134 if (res < 0) 1135 mfbi->count++; 1136 } 1137 spin_unlock(&diu_lock); 1138 return res; 1139} 1140 1141static struct fb_ops fsl_diu_ops = { 1142 .owner = THIS_MODULE, 1143 .fb_check_var = fsl_diu_check_var, 1144 .fb_set_par = fsl_diu_set_par, 1145 .fb_setcolreg = fsl_diu_setcolreg, 1146 .fb_blank = fsl_diu_blank, 1147 .fb_pan_display = fsl_diu_pan_display, 1148 .fb_fillrect = cfb_fillrect, 1149 .fb_copyarea = cfb_copyarea, 1150 .fb_imageblit = cfb_imageblit, 1151 .fb_ioctl = fsl_diu_ioctl, 1152 .fb_open = fsl_diu_open, 1153 .fb_release = fsl_diu_release, 1154}; 1155 1156static int init_fbinfo(struct fb_info *info) 1157{ 1158 struct mfb_info *mfbi = info->par; 1159 1160 info->device = NULL; 1161 info->var.activate = FB_ACTIVATE_NOW; 1162 info->fbops = &fsl_diu_ops; 1163 info->flags = FBINFO_FLAG_DEFAULT; 1164 info->pseudo_palette = &mfbi->pseudo_palette; 1165 1166 /* Allocate colormap */ 1167 fb_alloc_cmap(&info->cmap, 16, 0); 1168 return 0; 1169} 1170 1171static int __devinit install_fb(struct fb_info *info) 1172{ 1173 int rc; 1174 struct mfb_info *mfbi = info->par; 1175 const char *aoi_mode, *init_aoi_mode = "320x240"; 1176 1177 if (init_fbinfo(info)) 1178 return -EINVAL; 1179 1180 if (mfbi->index == 0) /* plane 0 */ 1181 aoi_mode = fb_mode; 1182 else 1183 aoi_mode = init_aoi_mode; 1184 pr_debug("mode used = %s\n", aoi_mode); 1185 rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db, 1186 ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp); 1187 1188 switch (rc) { 1189 case 1: 1190 pr_debug("using mode specified in @mode\n"); 1191 break; 1192 case 2: 1193 pr_debug("using mode specified in @mode " 1194 "with ignored refresh rate\n"); 1195 break; 1196 case 3: 1197 pr_debug("using mode default mode\n"); 1198 break; 1199 case 4: 1200 pr_debug("using mode from list\n"); 1201 break; 1202 default: 1203 pr_debug("rc = %d\n", rc); 1204 pr_debug("failed to find mode\n"); 1205 return -EINVAL; 1206 break; 1207 } 1208 1209 pr_debug("xres_virtual %d\n", info->var.xres_virtual); 1210 pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel); 1211 1212 pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual); 1213 pr_debug("info->fix.line_length = %d\n", info->fix.line_length); 1214 1215 if (mfbi->type == MFB_TYPE_OFF) 1216 mfbi->blank = FB_BLANK_NORMAL; 1217 else 1218 mfbi->blank = FB_BLANK_UNBLANK; 1219 1220 if (fsl_diu_check_var(&info->var, info)) { 1221 printk(KERN_ERR "fb_check_var failed"); 1222 fb_dealloc_cmap(&info->cmap); 1223 return -EINVAL; 1224 } 1225 1226 if (register_framebuffer(info) < 0) { 1227 printk(KERN_ERR "register_framebuffer failed"); 1228 unmap_video_memory(info); 1229 fb_dealloc_cmap(&info->cmap); 1230 return -EINVAL; 1231 } 1232 1233 mfbi->registered = 1; 1234 printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", 1235 info->node, info->fix.id); 1236 1237 return 0; 1238} 1239 1240static void uninstall_fb(struct fb_info *info) 1241{ 1242 struct mfb_info *mfbi = info->par; 1243 1244 if (!mfbi->registered) 1245 return; 1246 1247 unregister_framebuffer(info); 1248 unmap_video_memory(info); 1249 if (&info->cmap) 1250 fb_dealloc_cmap(&info->cmap); 1251 1252 mfbi->registered = 0; 1253} 1254 1255static irqreturn_t fsl_diu_isr(int irq, void *dev_id) 1256{ 1257 struct diu *hw = dr.diu_reg; 1258 unsigned int status = in_be32(&hw->int_status); 1259 1260 if (status) { 1261 /* This is the workaround for underrun */ 1262 if (status & INT_UNDRUN) { 1263 out_be32(&hw->diu_mode, 0); 1264 pr_debug("Err: DIU occurs underrun!\n"); 1265 udelay(1); 1266 out_be32(&hw->diu_mode, 1); 1267 } 1268#if defined(CONFIG_NOT_COHERENT_CACHE) 1269 else if (status & INT_VSYNC) { 1270 unsigned int i; 1271 for (i = 0; i < coherence_data_size; 1272 i += d_cache_line_size) 1273 __asm__ __volatile__ ( 1274 "dcbz 0, %[input]" 1275 ::[input]"r"(&coherence_data[i])); 1276 } 1277#endif 1278 return IRQ_HANDLED; 1279 } 1280 return IRQ_NONE; 1281} 1282 1283static int request_irq_local(int irq) 1284{ 1285 unsigned long status, ints; 1286 struct diu *hw; 1287 int ret; 1288 1289 hw = dr.diu_reg; 1290 1291 /* Read to clear the status */ 1292 status = in_be32(&hw->int_status); 1293 1294 ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL); 1295 if (ret) 1296 pr_info("Request diu IRQ failed.\n"); 1297 else { 1298 ints = INT_PARERR | INT_LS_BF_VS; 1299#if !defined(CONFIG_NOT_COHERENT_CACHE) 1300 ints |= INT_VSYNC; 1301#endif 1302 if (dr.mode == MFB_MODE2 || dr.mode == MFB_MODE3) 1303 ints |= INT_VSYNC_WB; 1304 1305 /* Read to clear the status */ 1306 status = in_be32(&hw->int_status); 1307 out_be32(&hw->int_mask, ints); 1308 } 1309 return ret; 1310} 1311 1312static void free_irq_local(int irq) 1313{ 1314 struct diu *hw = dr.diu_reg; 1315 1316 /* Disable all LCDC interrupt */ 1317 out_be32(&hw->int_mask, 0x1f); 1318 1319 free_irq(irq, NULL); 1320} 1321 1322#ifdef CONFIG_PM 1323/* 1324 * Power management hooks. Note that we won't be called from IRQ context, 1325 * unlike the blank functions above, so we may sleep. 1326 */ 1327static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state) 1328{ 1329 struct fsl_diu_data *machine_data; 1330 1331 machine_data = dev_get_drvdata(&ofdev->dev); 1332 disable_lcdc(machine_data->fsl_diu_info[0]); 1333 1334 return 0; 1335} 1336 1337static int fsl_diu_resume(struct of_device *ofdev) 1338{ 1339 struct fsl_diu_data *machine_data; 1340 1341 machine_data = dev_get_drvdata(&ofdev->dev); 1342 enable_lcdc(machine_data->fsl_diu_info[0]); 1343 1344 return 0; 1345} 1346 1347#else 1348#define fsl_diu_suspend NULL 1349#define fsl_diu_resume NULL 1350#endif /* CONFIG_PM */ 1351 1352/* Align to 64-bit(8-byte), 32-byte, etc. */ 1353static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, 1354 u32 bytes_align) 1355{ 1356 u32 offset, ssize; 1357 u32 mask; 1358 dma_addr_t paddr = 0; 1359 1360 ssize = size + bytes_align; 1361 buf->vaddr = dma_alloc_coherent(dev, ssize, &paddr, GFP_DMA | 1362 __GFP_ZERO); 1363 if (!buf->vaddr) 1364 return -ENOMEM; 1365 1366 buf->paddr = (__u32) paddr; 1367 1368 mask = bytes_align - 1; 1369 offset = (u32)buf->paddr & mask; 1370 if (offset) { 1371 buf->offset = bytes_align - offset; 1372 buf->paddr = (u32)buf->paddr + offset; 1373 } else 1374 buf->offset = 0; 1375 return 0; 1376} 1377 1378static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, 1379 u32 bytes_align) 1380{ 1381 dma_free_coherent(dev, size + bytes_align, 1382 buf->vaddr, (buf->paddr - buf->offset)); 1383 return; 1384} 1385 1386static ssize_t store_monitor(struct device *device, 1387 struct device_attribute *attr, const char *buf, size_t count) 1388{ 1389 int old_monitor_port; 1390 unsigned long val; 1391 struct fsl_diu_data *machine_data = 1392 container_of(attr, struct fsl_diu_data, dev_attr); 1393 1394 if (strict_strtoul(buf, 10, &val)) 1395 return 0; 1396 1397 old_monitor_port = machine_data->monitor_port; 1398 machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); 1399 1400 if (old_monitor_port != machine_data->monitor_port) { 1401 /* All AOIs need adjust pixel format 1402 * fsl_diu_set_par only change the pixsel format here 1403 * unlikely to fail. */ 1404 fsl_diu_set_par(machine_data->fsl_diu_info[0]); 1405 fsl_diu_set_par(machine_data->fsl_diu_info[1]); 1406 fsl_diu_set_par(machine_data->fsl_diu_info[2]); 1407 fsl_diu_set_par(machine_data->fsl_diu_info[3]); 1408 fsl_diu_set_par(machine_data->fsl_diu_info[4]); 1409 } 1410 return count; 1411} 1412 1413static ssize_t show_monitor(struct device *device, 1414 struct device_attribute *attr, char *buf) 1415{ 1416 struct fsl_diu_data *machine_data = 1417 container_of(attr, struct fsl_diu_data, dev_attr); 1418 return diu_ops.show_monitor_port(machine_data->monitor_port, buf); 1419} 1420 1421static int __devinit fsl_diu_probe(struct of_device *ofdev, 1422 const struct of_device_id *match) 1423{ 1424 struct device_node *np = ofdev->node; 1425 struct mfb_info *mfbi; 1426 phys_addr_t dummy_ad_addr; 1427 int ret, i, error = 0; 1428 struct resource res; 1429 struct fsl_diu_data *machine_data; 1430 1431 machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); 1432 if (!machine_data) 1433 return -ENOMEM; 1434 1435 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1436 machine_data->fsl_diu_info[i] = 1437 framebuffer_alloc(sizeof(struct mfb_info), &ofdev->dev); 1438 if (!machine_data->fsl_diu_info[i]) { 1439 dev_err(&ofdev->dev, "cannot allocate memory\n"); 1440 ret = -ENOMEM; 1441 goto error2; 1442 } 1443 mfbi = machine_data->fsl_diu_info[i]->par; 1444 memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); 1445 mfbi->parent = machine_data; 1446 } 1447 1448 ret = of_address_to_resource(np, 0, &res); 1449 if (ret) { 1450 dev_err(&ofdev->dev, "could not obtain DIU address\n"); 1451 goto error; 1452 } 1453 if (!res.start) { 1454 dev_err(&ofdev->dev, "invalid DIU address\n"); 1455 goto error; 1456 } 1457 dev_dbg(&ofdev->dev, "%s, res.start: 0x%08x\n", __func__, res.start); 1458 1459 dr.diu_reg = ioremap(res.start, sizeof(struct diu)); 1460 if (!dr.diu_reg) { 1461 dev_err(&ofdev->dev, "Err: can't map DIU registers!\n"); 1462 ret = -EFAULT; 1463 goto error2; 1464 } 1465 1466 out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/ 1467 1468 /* Get the IRQ of the DIU */ 1469 machine_data->irq = irq_of_parse_and_map(np, 0); 1470 1471 if (!machine_data->irq) { 1472 dev_err(&ofdev->dev, "could not get DIU IRQ\n"); 1473 ret = -EINVAL; 1474 goto error; 1475 } 1476 machine_data->monitor_port = monitor_port; 1477 1478 /* Area descriptor memory pool aligns to 64-bit boundary */ 1479 if (allocate_buf(&ofdev->dev, &pool.ad, 1480 sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) 1481 return -ENOMEM; 1482 1483 /* Get memory for Gamma Table - 32-byte aligned memory */ 1484 if (allocate_buf(&ofdev->dev, &pool.gamma, 768, 32)) { 1485 ret = -ENOMEM; 1486 goto error; 1487 } 1488 1489 /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ 1490 if (allocate_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1491 32)) { 1492 ret = -ENOMEM; 1493 goto error; 1494 } 1495 1496 i = ARRAY_SIZE(machine_data->fsl_diu_info); 1497 machine_data->dummy_ad = (struct diu_ad *) 1498 ((u32)pool.ad.vaddr + pool.ad.offset) + i; 1499 machine_data->dummy_ad->paddr = pool.ad.paddr + 1500 i * sizeof(struct diu_ad); 1501 machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); 1502 if (!machine_data->dummy_aoi_virt) { 1503 ret = -ENOMEM; 1504 goto error; 1505 } 1506 machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); 1507 machine_data->dummy_ad->pix_fmt = 0x88882317; 1508 machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); 1509 machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); 1510 machine_data->dummy_ad->offset_xyi = 0; 1511 machine_data->dummy_ad->offset_xyd = 0; 1512 machine_data->dummy_ad->next_ad = 0; 1513 1514 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr); 1515 out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr); 1516 out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr); 1517 1518 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { 1519 machine_data->fsl_diu_info[i]->fix.smem_start = 0; 1520 mfbi = machine_data->fsl_diu_info[i]->par; 1521 mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr 1522 + pool.ad.offset) + i; 1523 mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad); 1524 ret = install_fb(machine_data->fsl_diu_info[i]); 1525 if (ret) { 1526 dev_err(&ofdev->dev, 1527 "Failed to register framebuffer %d\n", 1528 i); 1529 goto error; 1530 } 1531 } 1532 1533 if (request_irq_local(machine_data->irq)) { 1534 dev_err(machine_data->fsl_diu_info[0]->dev, 1535 "could not request irq for diu."); 1536 goto error; 1537 } 1538 1539 machine_data->dev_attr.attr.name = "monitor"; 1540 machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; 1541 machine_data->dev_attr.show = show_monitor; 1542 machine_data->dev_attr.store = store_monitor; 1543 error = device_create_file(machine_data->fsl_diu_info[0]->dev, 1544 &machine_data->dev_attr); 1545 if (error) { 1546 dev_err(machine_data->fsl_diu_info[0]->dev, 1547 "could not create sysfs %s file\n", 1548 machine_data->dev_attr.attr.name); 1549 } 1550 1551 dev_set_drvdata(&ofdev->dev, machine_data); 1552 return 0; 1553 1554error: 1555 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); 1556 i > 0; i--) 1557 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1558 if (pool.ad.vaddr) 1559 free_buf(&ofdev->dev, &pool.ad, 1560 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1561 if (pool.gamma.vaddr) 1562 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1563 if (pool.cursor.vaddr) 1564 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1565 32); 1566 if (machine_data->dummy_aoi_virt) 1567 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1568 iounmap(dr.diu_reg); 1569 1570error2: 1571 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1572 if (machine_data->fsl_diu_info[i]) 1573 framebuffer_release(machine_data->fsl_diu_info[i]); 1574 kfree(machine_data); 1575 1576 return ret; 1577} 1578 1579 1580static int fsl_diu_remove(struct of_device *ofdev) 1581{ 1582 struct fsl_diu_data *machine_data; 1583 int i; 1584 1585 machine_data = dev_get_drvdata(&ofdev->dev); 1586 disable_lcdc(machine_data->fsl_diu_info[0]); 1587 free_irq_local(machine_data->irq); 1588 for (i = ARRAY_SIZE(machine_data->fsl_diu_info); i > 0; i--) 1589 uninstall_fb(machine_data->fsl_diu_info[i - 1]); 1590 if (pool.ad.vaddr) 1591 free_buf(&ofdev->dev, &pool.ad, 1592 sizeof(struct diu_ad) * FSL_AOI_NUM, 8); 1593 if (pool.gamma.vaddr) 1594 free_buf(&ofdev->dev, &pool.gamma, 768, 32); 1595 if (pool.cursor.vaddr) 1596 free_buf(&ofdev->dev, &pool.cursor, MAX_CURS * MAX_CURS * 2, 1597 32); 1598 if (machine_data->dummy_aoi_virt) 1599 fsl_diu_free(machine_data->dummy_aoi_virt, 64); 1600 iounmap(dr.diu_reg); 1601 for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) 1602 if (machine_data->fsl_diu_info[i]) 1603 framebuffer_release(machine_data->fsl_diu_info[i]); 1604 kfree(machine_data); 1605 1606 return 0; 1607} 1608 1609#ifndef MODULE 1610static int __init fsl_diu_setup(char *options) 1611{ 1612 char *opt; 1613 unsigned long val; 1614 1615 if (!options || !*options) 1616 return 0; 1617 1618 while ((opt = strsep(&options, ",")) != NULL) { 1619 if (!*opt) 1620 continue; 1621 if (!strncmp(opt, "monitor=", 8)) { 1622 if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) 1623 monitor_port = val; 1624 } else if (!strncmp(opt, "bpp=", 4)) { 1625 if (!strict_strtoul(opt + 4, 10, &val)) 1626 default_bpp = val; 1627 } else 1628 fb_mode = opt; 1629 } 1630 1631 return 0; 1632} 1633#endif 1634 1635static struct of_device_id fsl_diu_match[] = { 1636#ifdef CONFIG_PPC_MPC512x 1637 { 1638 .compatible = "fsl,mpc5121-diu", 1639 }, 1640#endif 1641 { 1642 .compatible = "fsl,diu", 1643 }, 1644 {} 1645}; 1646MODULE_DEVICE_TABLE(of, fsl_diu_match); 1647 1648static struct of_platform_driver fsl_diu_driver = { 1649 .owner = THIS_MODULE, 1650 .name = "fsl_diu", 1651 .match_table = fsl_diu_match, 1652 .probe = fsl_diu_probe, 1653 .remove = fsl_diu_remove, 1654 .suspend = fsl_diu_suspend, 1655 .resume = fsl_diu_resume, 1656}; 1657 1658static int __init fsl_diu_init(void) 1659{ 1660#ifdef CONFIG_NOT_COHERENT_CACHE 1661 struct device_node *np; 1662 const u32 *prop; 1663#endif 1664 int ret; 1665#ifndef MODULE 1666 char *option; 1667 1668 /* 1669 * For kernel boot options (in 'video=xxxfb:<options>' format) 1670 */ 1671 if (fb_get_options("fslfb", &option)) 1672 return -ENODEV; 1673 fsl_diu_setup(option); 1674#endif 1675 printk(KERN_INFO "Freescale DIU driver\n"); 1676 1677#ifdef CONFIG_NOT_COHERENT_CACHE 1678 np = of_find_node_by_type(NULL, "cpu"); 1679 if (!np) { 1680 printk(KERN_ERR "Err: can't find device node 'cpu'\n"); 1681 return -ENODEV; 1682 } 1683 1684 prop = of_get_property(np, "d-cache-size", NULL); 1685 if (prop == NULL) { 1686 of_node_put(np); 1687 return -ENODEV; 1688 } 1689 1690 /* Freescale PLRU requires 13/8 times the cache size to do a proper 1691 displacement flush 1692 */ 1693 coherence_data_size = *prop * 13; 1694 coherence_data_size /= 8; 1695 1696 prop = of_get_property(np, "d-cache-line-size", NULL); 1697 if (prop == NULL) { 1698 of_node_put(np); 1699 return -ENODEV; 1700 } 1701 d_cache_line_size = *prop; 1702 1703 of_node_put(np); 1704 coherence_data = vmalloc(coherence_data_size); 1705 if (!coherence_data) 1706 return -ENOMEM; 1707#endif 1708 ret = of_register_platform_driver(&fsl_diu_driver); 1709 if (ret) { 1710 printk(KERN_ERR 1711 "fsl-diu: failed to register platform driver\n"); 1712#if defined(CONFIG_NOT_COHERENT_CACHE) 1713 vfree(coherence_data); 1714#endif 1715 iounmap(dr.diu_reg); 1716 } 1717 return ret; 1718} 1719 1720static void __exit fsl_diu_exit(void) 1721{ 1722 of_unregister_platform_driver(&fsl_diu_driver); 1723#if defined(CONFIG_NOT_COHERENT_CACHE) 1724 vfree(coherence_data); 1725#endif 1726} 1727 1728module_init(fsl_diu_init); 1729module_exit(fsl_diu_exit); 1730 1731MODULE_AUTHOR("York Sun <yorksun@freescale.com>"); 1732MODULE_DESCRIPTION("Freescale DIU framebuffer driver"); 1733MODULE_LICENSE("GPL"); 1734 1735module_param_named(mode, fb_mode, charp, 0); 1736MODULE_PARM_DESC(mode, 1737 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); 1738module_param_named(bpp, default_bpp, ulong, 0); 1739MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); 1740module_param_named(monitor, monitor_port, int, 0); 1741MODULE_PARM_DESC(monitor, 1742 "Specify the monitor port (0, 1 or 2) if supported by the platform"); 1743