1 /* 2 * Framebuffer driver for TI OMAP boards 3 * 4 * Copyright (C) 2004 Nokia Corporation 5 * Author: Imre Deak <imre.deak@nokia.com> 6 * 7 * Acknowledgements: 8 * Alex McMains <aam@ridgerun.com> - Original driver 9 * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements 10 * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API 11 * Texas Instruments - H3 support 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 * This program is distributed in the hope that it will be useful, but 19 * WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License along 24 * with this program; if not, write to the Free Software Foundation, Inc., 25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 26 */ 27 #include <linux/platform_device.h> 28 #include <linux/mm.h> 29 #include <linux/slab.h> 30 #include <linux/uaccess.h> 31 #include <linux/module.h> 32 33 #include <linux/omap-dma.h> 34 35 #include <mach/hardware.h> 36 37 #include "omapfb.h" 38 #include "lcdc.h" 39 40 #define MODULE_NAME "omapfb" 41 42 static unsigned int def_accel; 43 static unsigned long def_vram[OMAPFB_PLANE_NUM]; 44 static unsigned int def_vram_cnt; 45 static unsigned long def_vxres; 46 static unsigned long def_vyres; 47 static unsigned int def_rotate; 48 static unsigned int def_mirror; 49 50 #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE 51 static bool manual_update = 1; 52 #else 53 static bool manual_update; 54 #endif 55 56 static struct platform_device *fbdev_pdev; 57 static struct lcd_panel *fbdev_panel; 58 static struct omapfb_device *omapfb_dev; 59 60 struct caps_table_struct { 61 unsigned long flag; 62 const char *name; 63 }; 64 65 static const struct caps_table_struct ctrl_caps[] = { 66 { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, 67 { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, 68 { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" }, 69 { OMAPFB_CAPS_PLANE_SCALE, "scale plane" }, 70 { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, 71 { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, 72 { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, 73 { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" }, 74 { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, 75 }; 76 77 static const struct caps_table_struct color_caps[] = { 78 { 1 << OMAPFB_COLOR_RGB565, "RGB565", }, 79 { 1 << OMAPFB_COLOR_YUV422, "YUV422", }, 80 { 1 << OMAPFB_COLOR_YUV420, "YUV420", }, 81 { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", }, 82 { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", }, 83 { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", }, 84 { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", }, 85 { 1 << OMAPFB_COLOR_RGB444, "RGB444", }, 86 { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, 87 }; 88 89 static void omapdss_release(struct device *dev) 90 { 91 } 92 93 /* dummy device for clocks */ 94 static struct platform_device omapdss_device = { 95 .name = "omapdss_dss", 96 .id = -1, 97 .dev = { 98 .release = omapdss_release, 99 }, 100 }; 101 102 /* 103 * --------------------------------------------------------------------------- 104 * LCD panel 105 * --------------------------------------------------------------------------- 106 */ 107 extern struct lcd_ctrl hwa742_ctrl; 108 109 static const struct lcd_ctrl *ctrls[] = { 110 &omap1_int_ctrl, 111 112 #ifdef CONFIG_FB_OMAP_LCDC_HWA742 113 &hwa742_ctrl, 114 #endif 115 }; 116 117 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 118 extern struct lcd_ctrl_extif omap1_ext_if; 119 #endif 120 121 static void omapfb_rqueue_lock(struct omapfb_device *fbdev) 122 { 123 mutex_lock(&fbdev->rqueue_mutex); 124 } 125 126 static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) 127 { 128 mutex_unlock(&fbdev->rqueue_mutex); 129 } 130 131 /* 132 * --------------------------------------------------------------------------- 133 * LCD controller and LCD DMA 134 * --------------------------------------------------------------------------- 135 */ 136 /* 137 * Allocate resources needed for LCD controller and LCD DMA operations. Video 138 * memory is allocated from system memory according to the virtual display 139 * size, except if a bigger memory size is specified explicitly as a kernel 140 * parameter. 141 */ 142 static int ctrl_init(struct omapfb_device *fbdev) 143 { 144 int r; 145 int i; 146 147 /* kernel/module vram parameters override boot tags/board config */ 148 if (def_vram_cnt) { 149 for (i = 0; i < def_vram_cnt; i++) 150 fbdev->mem_desc.region[i].size = 151 PAGE_ALIGN(def_vram[i]); 152 fbdev->mem_desc.region_cnt = i; 153 } 154 155 if (!fbdev->mem_desc.region_cnt) { 156 struct lcd_panel *panel = fbdev->panel; 157 int def_size; 158 int bpp = panel->bpp; 159 160 /* 12 bpp is packed in 16 bits */ 161 if (bpp == 12) 162 bpp = 16; 163 def_size = def_vxres * def_vyres * bpp / 8; 164 fbdev->mem_desc.region_cnt = 1; 165 fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size); 166 } 167 r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc); 168 if (r < 0) { 169 dev_err(fbdev->dev, "controller initialization failed (%d)\n", 170 r); 171 return r; 172 } 173 174 #ifdef DEBUG 175 for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 176 dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n", 177 i, 178 fbdev->mem_desc.region[i].paddr, 179 fbdev->mem_desc.region[i].vaddr, 180 fbdev->mem_desc.region[i].size); 181 } 182 #endif 183 return 0; 184 } 185 186 static void ctrl_cleanup(struct omapfb_device *fbdev) 187 { 188 fbdev->ctrl->cleanup(); 189 } 190 191 /* Must be called with fbdev->rqueue_mutex held. */ 192 static int ctrl_change_mode(struct fb_info *fbi) 193 { 194 int r; 195 unsigned long offset; 196 struct omapfb_plane_struct *plane = fbi->par; 197 struct omapfb_device *fbdev = plane->fbdev; 198 struct fb_var_screeninfo *var = &fbi->var; 199 200 offset = var->yoffset * fbi->fix.line_length + 201 var->xoffset * var->bits_per_pixel / 8; 202 203 if (fbdev->ctrl->sync) 204 fbdev->ctrl->sync(); 205 r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out, 206 offset, var->xres_virtual, 207 plane->info.pos_x, plane->info.pos_y, 208 var->xres, var->yres, plane->color_mode); 209 if (r < 0) 210 return r; 211 212 if (fbdev->ctrl->set_rotate != NULL) { 213 r = fbdev->ctrl->set_rotate(var->rotate); 214 if (r < 0) 215 return r; 216 } 217 218 if (fbdev->ctrl->set_scale != NULL) 219 r = fbdev->ctrl->set_scale(plane->idx, 220 var->xres, var->yres, 221 plane->info.out_width, 222 plane->info.out_height); 223 224 return r; 225 } 226 227 /* 228 * --------------------------------------------------------------------------- 229 * fbdev framework callbacks and the ioctl interface 230 * --------------------------------------------------------------------------- 231 */ 232 /* Called each time the omapfb device is opened */ 233 static int omapfb_open(struct fb_info *info, int user) 234 { 235 return 0; 236 } 237 238 static void omapfb_sync(struct fb_info *info); 239 240 /* Called when the omapfb device is closed. We make sure that any pending 241 * gfx DMA operations are ended, before we return. */ 242 static int omapfb_release(struct fb_info *info, int user) 243 { 244 omapfb_sync(info); 245 return 0; 246 } 247 248 /* Store a single color palette entry into a pseudo palette or the hardware 249 * palette if one is available. For now we support only 16bpp and thus store 250 * the entry only to the pseudo palette. 251 */ 252 static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green, 253 u_int blue, u_int transp, int update_hw_pal) 254 { 255 struct omapfb_plane_struct *plane = info->par; 256 struct omapfb_device *fbdev = plane->fbdev; 257 struct fb_var_screeninfo *var = &info->var; 258 int r = 0; 259 260 switch (plane->color_mode) { 261 case OMAPFB_COLOR_YUV422: 262 case OMAPFB_COLOR_YUV420: 263 case OMAPFB_COLOR_YUY422: 264 r = -EINVAL; 265 break; 266 case OMAPFB_COLOR_CLUT_8BPP: 267 case OMAPFB_COLOR_CLUT_4BPP: 268 case OMAPFB_COLOR_CLUT_2BPP: 269 case OMAPFB_COLOR_CLUT_1BPP: 270 if (fbdev->ctrl->setcolreg) 271 r = fbdev->ctrl->setcolreg(regno, red, green, blue, 272 transp, update_hw_pal); 273 /* Fallthrough */ 274 case OMAPFB_COLOR_RGB565: 275 case OMAPFB_COLOR_RGB444: 276 if (r != 0) 277 break; 278 279 if (regno < 16) { 280 u16 pal; 281 pal = ((red >> (16 - var->red.length)) << 282 var->red.offset) | 283 ((green >> (16 - var->green.length)) << 284 var->green.offset) | 285 (blue >> (16 - var->blue.length)); 286 ((u32 *)(info->pseudo_palette))[regno] = pal; 287 } 288 break; 289 default: 290 BUG(); 291 } 292 return r; 293 } 294 295 static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 296 u_int transp, struct fb_info *info) 297 { 298 return _setcolreg(info, regno, red, green, blue, transp, 1); 299 } 300 301 static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) 302 { 303 int count, index, r; 304 u16 *red, *green, *blue, *transp; 305 u16 trans = 0xffff; 306 307 red = cmap->red; 308 green = cmap->green; 309 blue = cmap->blue; 310 transp = cmap->transp; 311 index = cmap->start; 312 313 for (count = 0; count < cmap->len; count++) { 314 if (transp) 315 trans = *transp++; 316 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, 317 count == cmap->len - 1); 318 if (r != 0) 319 return r; 320 } 321 322 return 0; 323 } 324 325 static int omapfb_update_full_screen(struct fb_info *fbi); 326 327 static int omapfb_blank(int blank, struct fb_info *fbi) 328 { 329 struct omapfb_plane_struct *plane = fbi->par; 330 struct omapfb_device *fbdev = plane->fbdev; 331 int do_update = 0; 332 int r = 0; 333 334 omapfb_rqueue_lock(fbdev); 335 switch (blank) { 336 case FB_BLANK_UNBLANK: 337 if (fbdev->state == OMAPFB_SUSPENDED) { 338 if (fbdev->ctrl->resume) 339 fbdev->ctrl->resume(); 340 if (fbdev->panel->enable) 341 fbdev->panel->enable(fbdev->panel); 342 fbdev->state = OMAPFB_ACTIVE; 343 if (fbdev->ctrl->get_update_mode() == 344 OMAPFB_MANUAL_UPDATE) 345 do_update = 1; 346 } 347 break; 348 case FB_BLANK_POWERDOWN: 349 if (fbdev->state == OMAPFB_ACTIVE) { 350 if (fbdev->panel->disable) 351 fbdev->panel->disable(fbdev->panel); 352 if (fbdev->ctrl->suspend) 353 fbdev->ctrl->suspend(); 354 fbdev->state = OMAPFB_SUSPENDED; 355 } 356 break; 357 default: 358 r = -EINVAL; 359 } 360 omapfb_rqueue_unlock(fbdev); 361 362 if (r == 0 && do_update) 363 r = omapfb_update_full_screen(fbi); 364 365 return r; 366 } 367 368 static void omapfb_sync(struct fb_info *fbi) 369 { 370 struct omapfb_plane_struct *plane = fbi->par; 371 struct omapfb_device *fbdev = plane->fbdev; 372 373 omapfb_rqueue_lock(fbdev); 374 if (fbdev->ctrl->sync) 375 fbdev->ctrl->sync(); 376 omapfb_rqueue_unlock(fbdev); 377 } 378 379 /* 380 * Set fb_info.fix fields and also updates fbdev. 381 * When calling this fb_info.var must be set up already. 382 */ 383 static void set_fb_fix(struct fb_info *fbi, int from_init) 384 { 385 struct fb_fix_screeninfo *fix = &fbi->fix; 386 struct fb_var_screeninfo *var = &fbi->var; 387 struct omapfb_plane_struct *plane = fbi->par; 388 struct omapfb_mem_region *rg; 389 int bpp; 390 391 rg = &plane->fbdev->mem_desc.region[plane->idx]; 392 fbi->screen_base = rg->vaddr; 393 394 if (!from_init) { 395 mutex_lock(&fbi->mm_lock); 396 fix->smem_start = rg->paddr; 397 fix->smem_len = rg->size; 398 mutex_unlock(&fbi->mm_lock); 399 } else { 400 fix->smem_start = rg->paddr; 401 fix->smem_len = rg->size; 402 } 403 404 fix->type = FB_TYPE_PACKED_PIXELS; 405 bpp = var->bits_per_pixel; 406 if (var->nonstd) 407 fix->visual = FB_VISUAL_PSEUDOCOLOR; 408 else switch (var->bits_per_pixel) { 409 case 16: 410 case 12: 411 fix->visual = FB_VISUAL_TRUECOLOR; 412 /* 12bpp is stored in 16 bits */ 413 bpp = 16; 414 break; 415 case 1: 416 case 2: 417 case 4: 418 case 8: 419 fix->visual = FB_VISUAL_PSEUDOCOLOR; 420 break; 421 } 422 fix->accel = FB_ACCEL_OMAP1610; 423 fix->line_length = var->xres_virtual * bpp / 8; 424 } 425 426 static int set_color_mode(struct omapfb_plane_struct *plane, 427 struct fb_var_screeninfo *var) 428 { 429 switch (var->nonstd) { 430 case 0: 431 break; 432 case OMAPFB_COLOR_YUV422: 433 var->bits_per_pixel = 16; 434 plane->color_mode = var->nonstd; 435 return 0; 436 case OMAPFB_COLOR_YUV420: 437 var->bits_per_pixel = 12; 438 plane->color_mode = var->nonstd; 439 return 0; 440 case OMAPFB_COLOR_YUY422: 441 var->bits_per_pixel = 16; 442 plane->color_mode = var->nonstd; 443 return 0; 444 default: 445 return -EINVAL; 446 } 447 448 switch (var->bits_per_pixel) { 449 case 1: 450 plane->color_mode = OMAPFB_COLOR_CLUT_1BPP; 451 return 0; 452 case 2: 453 plane->color_mode = OMAPFB_COLOR_CLUT_2BPP; 454 return 0; 455 case 4: 456 plane->color_mode = OMAPFB_COLOR_CLUT_4BPP; 457 return 0; 458 case 8: 459 plane->color_mode = OMAPFB_COLOR_CLUT_8BPP; 460 return 0; 461 case 12: 462 var->bits_per_pixel = 16; 463 case 16: 464 if (plane->fbdev->panel->bpp == 12) 465 plane->color_mode = OMAPFB_COLOR_RGB444; 466 else 467 plane->color_mode = OMAPFB_COLOR_RGB565; 468 return 0; 469 default: 470 return -EINVAL; 471 } 472 } 473 474 /* 475 * Check the values in var against our capabilities and in case of out of 476 * bound values try to adjust them. 477 */ 478 static int set_fb_var(struct fb_info *fbi, 479 struct fb_var_screeninfo *var) 480 { 481 int bpp; 482 unsigned long max_frame_size; 483 unsigned long line_size; 484 int xres_min, xres_max; 485 int yres_min, yres_max; 486 struct omapfb_plane_struct *plane = fbi->par; 487 struct omapfb_device *fbdev = plane->fbdev; 488 struct lcd_panel *panel = fbdev->panel; 489 490 if (set_color_mode(plane, var) < 0) 491 return -EINVAL; 492 493 bpp = var->bits_per_pixel; 494 if (plane->color_mode == OMAPFB_COLOR_RGB444) 495 bpp = 16; 496 497 switch (var->rotate) { 498 case 0: 499 case 180: 500 xres_min = OMAPFB_PLANE_XRES_MIN; 501 xres_max = panel->x_res; 502 yres_min = OMAPFB_PLANE_YRES_MIN; 503 yres_max = panel->y_res; 504 if (cpu_is_omap15xx()) { 505 var->xres = panel->x_res; 506 var->yres = panel->y_res; 507 } 508 break; 509 case 90: 510 case 270: 511 xres_min = OMAPFB_PLANE_YRES_MIN; 512 xres_max = panel->y_res; 513 yres_min = OMAPFB_PLANE_XRES_MIN; 514 yres_max = panel->x_res; 515 if (cpu_is_omap15xx()) { 516 var->xres = panel->y_res; 517 var->yres = panel->x_res; 518 } 519 break; 520 default: 521 return -EINVAL; 522 } 523 524 if (var->xres < xres_min) 525 var->xres = xres_min; 526 if (var->yres < yres_min) 527 var->yres = yres_min; 528 if (var->xres > xres_max) 529 var->xres = xres_max; 530 if (var->yres > yres_max) 531 var->yres = yres_max; 532 533 if (var->xres_virtual < var->xres) 534 var->xres_virtual = var->xres; 535 if (var->yres_virtual < var->yres) 536 var->yres_virtual = var->yres; 537 max_frame_size = fbdev->mem_desc.region[plane->idx].size; 538 line_size = var->xres_virtual * bpp / 8; 539 if (line_size * var->yres_virtual > max_frame_size) { 540 /* Try to keep yres_virtual first */ 541 line_size = max_frame_size / var->yres_virtual; 542 var->xres_virtual = line_size * 8 / bpp; 543 if (var->xres_virtual < var->xres) { 544 /* Still doesn't fit. Shrink yres_virtual too */ 545 var->xres_virtual = var->xres; 546 line_size = var->xres * bpp / 8; 547 var->yres_virtual = max_frame_size / line_size; 548 } 549 /* Recheck this, as the virtual size changed. */ 550 if (var->xres_virtual < var->xres) 551 var->xres = var->xres_virtual; 552 if (var->yres_virtual < var->yres) 553 var->yres = var->yres_virtual; 554 if (var->xres < xres_min || var->yres < yres_min) 555 return -EINVAL; 556 } 557 if (var->xres + var->xoffset > var->xres_virtual) 558 var->xoffset = var->xres_virtual - var->xres; 559 if (var->yres + var->yoffset > var->yres_virtual) 560 var->yoffset = var->yres_virtual - var->yres; 561 562 if (plane->color_mode == OMAPFB_COLOR_RGB444) { 563 var->red.offset = 8; var->red.length = 4; 564 var->red.msb_right = 0; 565 var->green.offset = 4; var->green.length = 4; 566 var->green.msb_right = 0; 567 var->blue.offset = 0; var->blue.length = 4; 568 var->blue.msb_right = 0; 569 } else { 570 var->red.offset = 11; var->red.length = 5; 571 var->red.msb_right = 0; 572 var->green.offset = 5; var->green.length = 6; 573 var->green.msb_right = 0; 574 var->blue.offset = 0; var->blue.length = 5; 575 var->blue.msb_right = 0; 576 } 577 578 var->height = -1; 579 var->width = -1; 580 var->grayscale = 0; 581 582 /* pixclock in ps, the rest in pixclock */ 583 var->pixclock = 10000000 / (panel->pixel_clock / 100); 584 var->left_margin = panel->hfp; 585 var->right_margin = panel->hbp; 586 var->upper_margin = panel->vfp; 587 var->lower_margin = panel->vbp; 588 var->hsync_len = panel->hsw; 589 var->vsync_len = panel->vsw; 590 591 /* TODO: get these from panel->config */ 592 var->vmode = FB_VMODE_NONINTERLACED; 593 var->sync = 0; 594 595 return 0; 596 } 597 598 599 /* 600 * Set new x,y offsets in the virtual display for the visible area and switch 601 * to the new mode. 602 */ 603 static int omapfb_pan_display(struct fb_var_screeninfo *var, 604 struct fb_info *fbi) 605 { 606 struct omapfb_plane_struct *plane = fbi->par; 607 struct omapfb_device *fbdev = plane->fbdev; 608 int r = 0; 609 610 omapfb_rqueue_lock(fbdev); 611 if (var->xoffset != fbi->var.xoffset || 612 var->yoffset != fbi->var.yoffset) { 613 struct fb_var_screeninfo *new_var = &fbdev->new_var; 614 615 memcpy(new_var, &fbi->var, sizeof(*new_var)); 616 new_var->xoffset = var->xoffset; 617 new_var->yoffset = var->yoffset; 618 if (set_fb_var(fbi, new_var)) 619 r = -EINVAL; 620 else { 621 memcpy(&fbi->var, new_var, sizeof(*new_var)); 622 ctrl_change_mode(fbi); 623 } 624 } 625 omapfb_rqueue_unlock(fbdev); 626 627 return r; 628 } 629 630 /* Set mirror to vertical axis and switch to the new mode. */ 631 static int omapfb_mirror(struct fb_info *fbi, int mirror) 632 { 633 struct omapfb_plane_struct *plane = fbi->par; 634 struct omapfb_device *fbdev = plane->fbdev; 635 int r = 0; 636 637 omapfb_rqueue_lock(fbdev); 638 mirror = mirror ? 1 : 0; 639 if (cpu_is_omap15xx()) 640 r = -EINVAL; 641 else if (mirror != plane->info.mirror) { 642 plane->info.mirror = mirror; 643 r = ctrl_change_mode(fbi); 644 } 645 omapfb_rqueue_unlock(fbdev); 646 647 return r; 648 } 649 650 /* 651 * Check values in var, try to adjust them in case of out of bound values if 652 * possible, or return error. 653 */ 654 static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) 655 { 656 struct omapfb_plane_struct *plane = fbi->par; 657 struct omapfb_device *fbdev = plane->fbdev; 658 int r; 659 660 omapfb_rqueue_lock(fbdev); 661 if (fbdev->ctrl->sync != NULL) 662 fbdev->ctrl->sync(); 663 r = set_fb_var(fbi, var); 664 omapfb_rqueue_unlock(fbdev); 665 666 return r; 667 } 668 669 /* 670 * Switch to a new mode. The parameters for it has been check already by 671 * omapfb_check_var. 672 */ 673 static int omapfb_set_par(struct fb_info *fbi) 674 { 675 struct omapfb_plane_struct *plane = fbi->par; 676 struct omapfb_device *fbdev = plane->fbdev; 677 int r = 0; 678 679 omapfb_rqueue_lock(fbdev); 680 set_fb_fix(fbi, 0); 681 r = ctrl_change_mode(fbi); 682 omapfb_rqueue_unlock(fbdev); 683 684 return r; 685 } 686 687 int omapfb_update_window_async(struct fb_info *fbi, 688 struct omapfb_update_window *win, 689 void (*callback)(void *), 690 void *callback_data) 691 { 692 int xres, yres; 693 struct omapfb_plane_struct *plane = fbi->par; 694 struct omapfb_device *fbdev = plane->fbdev; 695 struct fb_var_screeninfo *var = &fbi->var; 696 697 switch (var->rotate) { 698 case 0: 699 case 180: 700 xres = fbdev->panel->x_res; 701 yres = fbdev->panel->y_res; 702 break; 703 case 90: 704 case 270: 705 xres = fbdev->panel->y_res; 706 yres = fbdev->panel->x_res; 707 break; 708 default: 709 return -EINVAL; 710 } 711 712 if (win->x >= xres || win->y >= yres || 713 win->out_x > xres || win->out_y > yres) 714 return -EINVAL; 715 716 if (!fbdev->ctrl->update_window || 717 fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) 718 return -ENODEV; 719 720 if (win->x + win->width > xres) 721 win->width = xres - win->x; 722 if (win->y + win->height > yres) 723 win->height = yres - win->y; 724 if (win->out_x + win->out_width > xres) 725 win->out_width = xres - win->out_x; 726 if (win->out_y + win->out_height > yres) 727 win->out_height = yres - win->out_y; 728 if (!win->width || !win->height || !win->out_width || !win->out_height) 729 return 0; 730 731 return fbdev->ctrl->update_window(fbi, win, callback, callback_data); 732 } 733 EXPORT_SYMBOL(omapfb_update_window_async); 734 735 static int omapfb_update_win(struct fb_info *fbi, 736 struct omapfb_update_window *win) 737 { 738 struct omapfb_plane_struct *plane = fbi->par; 739 int ret; 740 741 omapfb_rqueue_lock(plane->fbdev); 742 ret = omapfb_update_window_async(fbi, win, NULL, NULL); 743 omapfb_rqueue_unlock(plane->fbdev); 744 745 return ret; 746 } 747 748 static int omapfb_update_full_screen(struct fb_info *fbi) 749 { 750 struct omapfb_plane_struct *plane = fbi->par; 751 struct omapfb_device *fbdev = plane->fbdev; 752 struct omapfb_update_window win; 753 int r; 754 755 if (!fbdev->ctrl->update_window || 756 fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) 757 return -ENODEV; 758 759 win.x = 0; 760 win.y = 0; 761 win.width = fbi->var.xres; 762 win.height = fbi->var.yres; 763 win.out_x = 0; 764 win.out_y = 0; 765 win.out_width = fbi->var.xres; 766 win.out_height = fbi->var.yres; 767 win.format = 0; 768 769 omapfb_rqueue_lock(fbdev); 770 r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL); 771 omapfb_rqueue_unlock(fbdev); 772 773 return r; 774 } 775 776 static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 777 { 778 struct omapfb_plane_struct *plane = fbi->par; 779 struct omapfb_device *fbdev = plane->fbdev; 780 struct lcd_panel *panel = fbdev->panel; 781 struct omapfb_plane_info old_info; 782 int r = 0; 783 784 if (pi->pos_x + pi->out_width > panel->x_res || 785 pi->pos_y + pi->out_height > panel->y_res) 786 return -EINVAL; 787 788 omapfb_rqueue_lock(fbdev); 789 if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { 790 /* 791 * This plane's memory was freed, can't enable it 792 * until it's reallocated. 793 */ 794 r = -EINVAL; 795 goto out; 796 } 797 old_info = plane->info; 798 plane->info = *pi; 799 if (pi->enabled) { 800 r = ctrl_change_mode(fbi); 801 if (r < 0) { 802 plane->info = old_info; 803 goto out; 804 } 805 } 806 r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); 807 if (r < 0) { 808 plane->info = old_info; 809 goto out; 810 } 811 out: 812 omapfb_rqueue_unlock(fbdev); 813 return r; 814 } 815 816 static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 817 { 818 struct omapfb_plane_struct *plane = fbi->par; 819 820 *pi = plane->info; 821 return 0; 822 } 823 824 static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 825 { 826 struct omapfb_plane_struct *plane = fbi->par; 827 struct omapfb_device *fbdev = plane->fbdev; 828 struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; 829 size_t size; 830 int r = 0; 831 832 if (fbdev->ctrl->setup_mem == NULL) 833 return -ENODEV; 834 if (mi->type != OMAPFB_MEMTYPE_SDRAM) 835 return -EINVAL; 836 837 size = PAGE_ALIGN(mi->size); 838 omapfb_rqueue_lock(fbdev); 839 if (plane->info.enabled) { 840 r = -EBUSY; 841 goto out; 842 } 843 if (rg->size != size || rg->type != mi->type) { 844 struct fb_var_screeninfo *new_var = &fbdev->new_var; 845 unsigned long old_size = rg->size; 846 u8 old_type = rg->type; 847 unsigned long paddr; 848 849 rg->size = size; 850 rg->type = mi->type; 851 /* 852 * size == 0 is a special case, for which we 853 * don't check / adjust the screen parameters. 854 * This isn't a problem since the plane can't 855 * be reenabled unless its size is > 0. 856 */ 857 if (old_size != size && size) { 858 if (size) { 859 memcpy(new_var, &fbi->var, sizeof(*new_var)); 860 r = set_fb_var(fbi, new_var); 861 if (r < 0) 862 goto out; 863 } 864 } 865 866 if (fbdev->ctrl->sync) 867 fbdev->ctrl->sync(); 868 r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); 869 if (r < 0) { 870 /* Revert changes. */ 871 rg->size = old_size; 872 rg->type = old_type; 873 goto out; 874 } 875 rg->paddr = paddr; 876 877 if (old_size != size) { 878 if (size) { 879 memcpy(&fbi->var, new_var, sizeof(fbi->var)); 880 set_fb_fix(fbi, 0); 881 } else { 882 /* 883 * Set these explicitly to indicate that the 884 * plane memory is dealloce'd, the other 885 * screen parameters in var / fix are invalid. 886 */ 887 mutex_lock(&fbi->mm_lock); 888 fbi->fix.smem_start = 0; 889 fbi->fix.smem_len = 0; 890 mutex_unlock(&fbi->mm_lock); 891 } 892 } 893 } 894 out: 895 omapfb_rqueue_unlock(fbdev); 896 897 return r; 898 } 899 900 static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 901 { 902 struct omapfb_plane_struct *plane = fbi->par; 903 struct omapfb_device *fbdev = plane->fbdev; 904 struct omapfb_mem_region *rg; 905 906 rg = &fbdev->mem_desc.region[plane->idx]; 907 memset(mi, 0, sizeof(*mi)); 908 mi->size = rg->size; 909 mi->type = rg->type; 910 911 return 0; 912 } 913 914 static int omapfb_set_color_key(struct omapfb_device *fbdev, 915 struct omapfb_color_key *ck) 916 { 917 int r; 918 919 if (!fbdev->ctrl->set_color_key) 920 return -ENODEV; 921 922 omapfb_rqueue_lock(fbdev); 923 r = fbdev->ctrl->set_color_key(ck); 924 omapfb_rqueue_unlock(fbdev); 925 926 return r; 927 } 928 929 static int omapfb_get_color_key(struct omapfb_device *fbdev, 930 struct omapfb_color_key *ck) 931 { 932 int r; 933 934 if (!fbdev->ctrl->get_color_key) 935 return -ENODEV; 936 937 omapfb_rqueue_lock(fbdev); 938 r = fbdev->ctrl->get_color_key(ck); 939 omapfb_rqueue_unlock(fbdev); 940 941 return r; 942 } 943 944 static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM]; 945 static int notifier_inited; 946 947 static void omapfb_init_notifier(void) 948 { 949 int i; 950 951 for (i = 0; i < OMAPFB_PLANE_NUM; i++) 952 BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]); 953 } 954 955 int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, 956 omapfb_notifier_callback_t callback, 957 void *callback_data) 958 { 959 int r; 960 961 if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM) 962 return -EINVAL; 963 964 if (!notifier_inited) { 965 omapfb_init_notifier(); 966 notifier_inited = 1; 967 } 968 969 omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, 970 unsigned long, void *))callback; 971 omapfb_nb->data = callback_data; 972 r = blocking_notifier_chain_register( 973 &omapfb_client_list[omapfb_nb->plane_idx], 974 &omapfb_nb->nb); 975 if (r) 976 return r; 977 if (omapfb_dev != NULL && 978 omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) { 979 omapfb_dev->ctrl->bind_client(omapfb_nb); 980 } 981 982 return 0; 983 } 984 EXPORT_SYMBOL(omapfb_register_client); 985 986 int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb) 987 { 988 return blocking_notifier_chain_unregister( 989 &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb); 990 } 991 EXPORT_SYMBOL(omapfb_unregister_client); 992 993 void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event) 994 { 995 int i; 996 997 if (!notifier_inited) 998 /* no client registered yet */ 999 return; 1000 1001 for (i = 0; i < OMAPFB_PLANE_NUM; i++) 1002 blocking_notifier_call_chain(&omapfb_client_list[i], event, 1003 fbdev->fb_info[i]); 1004 } 1005 EXPORT_SYMBOL(omapfb_notify_clients); 1006 1007 static int omapfb_set_update_mode(struct omapfb_device *fbdev, 1008 enum omapfb_update_mode mode) 1009 { 1010 int r; 1011 1012 omapfb_rqueue_lock(fbdev); 1013 r = fbdev->ctrl->set_update_mode(mode); 1014 omapfb_rqueue_unlock(fbdev); 1015 1016 return r; 1017 } 1018 1019 static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) 1020 { 1021 int r; 1022 1023 omapfb_rqueue_lock(fbdev); 1024 r = fbdev->ctrl->get_update_mode(); 1025 omapfb_rqueue_unlock(fbdev); 1026 1027 return r; 1028 } 1029 1030 static void omapfb_get_caps(struct omapfb_device *fbdev, int plane, 1031 struct omapfb_caps *caps) 1032 { 1033 memset(caps, 0, sizeof(*caps)); 1034 fbdev->ctrl->get_caps(plane, caps); 1035 if (fbdev->panel->get_caps) 1036 caps->ctrl |= fbdev->panel->get_caps(fbdev->panel); 1037 } 1038 1039 /* For lcd testing */ 1040 void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval) 1041 { 1042 omapfb_rqueue_lock(fbdev); 1043 *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval; 1044 if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) { 1045 struct omapfb_update_window win; 1046 1047 memset(&win, 0, sizeof(win)); 1048 win.width = 2; 1049 win.height = 2; 1050 win.out_width = 2; 1051 win.out_height = 2; 1052 fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL); 1053 } 1054 omapfb_rqueue_unlock(fbdev); 1055 } 1056 EXPORT_SYMBOL(omapfb_write_first_pixel); 1057 1058 /* 1059 * Ioctl interface. Part of the kernel mode frame buffer API is duplicated 1060 * here to be accessible by user mode code. 1061 */ 1062 static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, 1063 unsigned long arg) 1064 { 1065 struct omapfb_plane_struct *plane = fbi->par; 1066 struct omapfb_device *fbdev = plane->fbdev; 1067 struct fb_ops *ops = fbi->fbops; 1068 union { 1069 struct omapfb_update_window update_window; 1070 struct omapfb_plane_info plane_info; 1071 struct omapfb_mem_info mem_info; 1072 struct omapfb_color_key color_key; 1073 enum omapfb_update_mode update_mode; 1074 struct omapfb_caps caps; 1075 unsigned int mirror; 1076 int plane_out; 1077 int enable_plane; 1078 } p; 1079 int r = 0; 1080 1081 BUG_ON(!ops); 1082 switch (cmd) { 1083 case OMAPFB_MIRROR: 1084 if (get_user(p.mirror, (int __user *)arg)) 1085 r = -EFAULT; 1086 else 1087 omapfb_mirror(fbi, p.mirror); 1088 break; 1089 case OMAPFB_SYNC_GFX: 1090 omapfb_sync(fbi); 1091 break; 1092 case OMAPFB_VSYNC: 1093 break; 1094 case OMAPFB_SET_UPDATE_MODE: 1095 if (get_user(p.update_mode, (int __user *)arg)) 1096 r = -EFAULT; 1097 else 1098 r = omapfb_set_update_mode(fbdev, p.update_mode); 1099 break; 1100 case OMAPFB_GET_UPDATE_MODE: 1101 p.update_mode = omapfb_get_update_mode(fbdev); 1102 if (put_user(p.update_mode, 1103 (enum omapfb_update_mode __user *)arg)) 1104 r = -EFAULT; 1105 break; 1106 case OMAPFB_UPDATE_WINDOW_OLD: 1107 if (copy_from_user(&p.update_window, (void __user *)arg, 1108 sizeof(struct omapfb_update_window_old))) 1109 r = -EFAULT; 1110 else { 1111 struct omapfb_update_window *u = &p.update_window; 1112 u->out_x = u->x; 1113 u->out_y = u->y; 1114 u->out_width = u->width; 1115 u->out_height = u->height; 1116 memset(u->reserved, 0, sizeof(u->reserved)); 1117 r = omapfb_update_win(fbi, u); 1118 } 1119 break; 1120 case OMAPFB_UPDATE_WINDOW: 1121 if (copy_from_user(&p.update_window, (void __user *)arg, 1122 sizeof(p.update_window))) 1123 r = -EFAULT; 1124 else 1125 r = omapfb_update_win(fbi, &p.update_window); 1126 break; 1127 case OMAPFB_SETUP_PLANE: 1128 if (copy_from_user(&p.plane_info, (void __user *)arg, 1129 sizeof(p.plane_info))) 1130 r = -EFAULT; 1131 else 1132 r = omapfb_setup_plane(fbi, &p.plane_info); 1133 break; 1134 case OMAPFB_QUERY_PLANE: 1135 if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0) 1136 break; 1137 if (copy_to_user((void __user *)arg, &p.plane_info, 1138 sizeof(p.plane_info))) 1139 r = -EFAULT; 1140 break; 1141 case OMAPFB_SETUP_MEM: 1142 if (copy_from_user(&p.mem_info, (void __user *)arg, 1143 sizeof(p.mem_info))) 1144 r = -EFAULT; 1145 else 1146 r = omapfb_setup_mem(fbi, &p.mem_info); 1147 break; 1148 case OMAPFB_QUERY_MEM: 1149 if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0) 1150 break; 1151 if (copy_to_user((void __user *)arg, &p.mem_info, 1152 sizeof(p.mem_info))) 1153 r = -EFAULT; 1154 break; 1155 case OMAPFB_SET_COLOR_KEY: 1156 if (copy_from_user(&p.color_key, (void __user *)arg, 1157 sizeof(p.color_key))) 1158 r = -EFAULT; 1159 else 1160 r = omapfb_set_color_key(fbdev, &p.color_key); 1161 break; 1162 case OMAPFB_GET_COLOR_KEY: 1163 if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0) 1164 break; 1165 if (copy_to_user((void __user *)arg, &p.color_key, 1166 sizeof(p.color_key))) 1167 r = -EFAULT; 1168 break; 1169 case OMAPFB_GET_CAPS: 1170 omapfb_get_caps(fbdev, plane->idx, &p.caps); 1171 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) 1172 r = -EFAULT; 1173 break; 1174 case OMAPFB_LCD_TEST: 1175 { 1176 int test_num; 1177 1178 if (get_user(test_num, (int __user *)arg)) { 1179 r = -EFAULT; 1180 break; 1181 } 1182 if (!fbdev->panel->run_test) { 1183 r = -EINVAL; 1184 break; 1185 } 1186 r = fbdev->panel->run_test(fbdev->panel, test_num); 1187 break; 1188 } 1189 case OMAPFB_CTRL_TEST: 1190 { 1191 int test_num; 1192 1193 if (get_user(test_num, (int __user *)arg)) { 1194 r = -EFAULT; 1195 break; 1196 } 1197 if (!fbdev->ctrl->run_test) { 1198 r = -EINVAL; 1199 break; 1200 } 1201 r = fbdev->ctrl->run_test(test_num); 1202 break; 1203 } 1204 default: 1205 r = -EINVAL; 1206 } 1207 1208 return r; 1209 } 1210 1211 static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 1212 { 1213 struct omapfb_plane_struct *plane = info->par; 1214 struct omapfb_device *fbdev = plane->fbdev; 1215 int r; 1216 1217 omapfb_rqueue_lock(fbdev); 1218 r = fbdev->ctrl->mmap(info, vma); 1219 omapfb_rqueue_unlock(fbdev); 1220 1221 return r; 1222 } 1223 1224 /* 1225 * Callback table for the frame buffer framework. Some of these pointers 1226 * will be changed according to the current setting of fb_info->accel_flags. 1227 */ 1228 static struct fb_ops omapfb_ops = { 1229 .owner = THIS_MODULE, 1230 .fb_open = omapfb_open, 1231 .fb_release = omapfb_release, 1232 .fb_setcolreg = omapfb_setcolreg, 1233 .fb_setcmap = omapfb_setcmap, 1234 .fb_fillrect = cfb_fillrect, 1235 .fb_copyarea = cfb_copyarea, 1236 .fb_imageblit = cfb_imageblit, 1237 .fb_blank = omapfb_blank, 1238 .fb_ioctl = omapfb_ioctl, 1239 .fb_check_var = omapfb_check_var, 1240 .fb_set_par = omapfb_set_par, 1241 .fb_pan_display = omapfb_pan_display, 1242 }; 1243 1244 /* 1245 * --------------------------------------------------------------------------- 1246 * Sysfs interface 1247 * --------------------------------------------------------------------------- 1248 */ 1249 /* omapfbX sysfs entries */ 1250 static ssize_t omapfb_show_caps_num(struct device *dev, 1251 struct device_attribute *attr, char *buf) 1252 { 1253 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1254 int plane; 1255 size_t size; 1256 struct omapfb_caps caps; 1257 1258 plane = 0; 1259 size = 0; 1260 while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { 1261 omapfb_get_caps(fbdev, plane, &caps); 1262 size += snprintf(&buf[size], PAGE_SIZE - size, 1263 "plane#%d %#010x %#010x %#010x\n", 1264 plane, caps.ctrl, caps.plane_color, caps.wnd_color); 1265 plane++; 1266 } 1267 return size; 1268 } 1269 1270 static ssize_t omapfb_show_caps_text(struct device *dev, 1271 struct device_attribute *attr, char *buf) 1272 { 1273 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1274 int i; 1275 struct omapfb_caps caps; 1276 int plane; 1277 size_t size; 1278 1279 plane = 0; 1280 size = 0; 1281 while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { 1282 omapfb_get_caps(fbdev, plane, &caps); 1283 size += snprintf(&buf[size], PAGE_SIZE - size, 1284 "plane#%d:\n", plane); 1285 for (i = 0; i < ARRAY_SIZE(ctrl_caps) && 1286 size < PAGE_SIZE; i++) { 1287 if (ctrl_caps[i].flag & caps.ctrl) 1288 size += snprintf(&buf[size], PAGE_SIZE - size, 1289 " %s\n", ctrl_caps[i].name); 1290 } 1291 size += snprintf(&buf[size], PAGE_SIZE - size, 1292 " plane colors:\n"); 1293 for (i = 0; i < ARRAY_SIZE(color_caps) && 1294 size < PAGE_SIZE; i++) { 1295 if (color_caps[i].flag & caps.plane_color) 1296 size += snprintf(&buf[size], PAGE_SIZE - size, 1297 " %s\n", color_caps[i].name); 1298 } 1299 size += snprintf(&buf[size], PAGE_SIZE - size, 1300 " window colors:\n"); 1301 for (i = 0; i < ARRAY_SIZE(color_caps) && 1302 size < PAGE_SIZE; i++) { 1303 if (color_caps[i].flag & caps.wnd_color) 1304 size += snprintf(&buf[size], PAGE_SIZE - size, 1305 " %s\n", color_caps[i].name); 1306 } 1307 1308 plane++; 1309 } 1310 return size; 1311 } 1312 1313 static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); 1314 static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); 1315 1316 /* panel sysfs entries */ 1317 static ssize_t omapfb_show_panel_name(struct device *dev, 1318 struct device_attribute *attr, char *buf) 1319 { 1320 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1321 1322 return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); 1323 } 1324 1325 static ssize_t omapfb_show_bklight_level(struct device *dev, 1326 struct device_attribute *attr, 1327 char *buf) 1328 { 1329 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1330 int r; 1331 1332 if (fbdev->panel->get_bklight_level) { 1333 r = snprintf(buf, PAGE_SIZE, "%d\n", 1334 fbdev->panel->get_bklight_level(fbdev->panel)); 1335 } else 1336 r = -ENODEV; 1337 return r; 1338 } 1339 1340 static ssize_t omapfb_store_bklight_level(struct device *dev, 1341 struct device_attribute *attr, 1342 const char *buf, size_t size) 1343 { 1344 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1345 int r; 1346 1347 if (fbdev->panel->set_bklight_level) { 1348 unsigned int level; 1349 1350 if (sscanf(buf, "%10d", &level) == 1) { 1351 r = fbdev->panel->set_bklight_level(fbdev->panel, 1352 level); 1353 } else 1354 r = -EINVAL; 1355 } else 1356 r = -ENODEV; 1357 return r ? r : size; 1358 } 1359 1360 static ssize_t omapfb_show_bklight_max(struct device *dev, 1361 struct device_attribute *attr, char *buf) 1362 { 1363 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1364 int r; 1365 1366 if (fbdev->panel->get_bklight_level) { 1367 r = snprintf(buf, PAGE_SIZE, "%d\n", 1368 fbdev->panel->get_bklight_max(fbdev->panel)); 1369 } else 1370 r = -ENODEV; 1371 return r; 1372 } 1373 1374 static struct device_attribute dev_attr_panel_name = 1375 __ATTR(name, 0444, omapfb_show_panel_name, NULL); 1376 static DEVICE_ATTR(backlight_level, 0664, 1377 omapfb_show_bklight_level, omapfb_store_bklight_level); 1378 static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); 1379 1380 static struct attribute *panel_attrs[] = { 1381 &dev_attr_panel_name.attr, 1382 &dev_attr_backlight_level.attr, 1383 &dev_attr_backlight_max.attr, 1384 NULL, 1385 }; 1386 1387 static const struct attribute_group panel_attr_grp = { 1388 .name = "panel", 1389 .attrs = panel_attrs, 1390 }; 1391 1392 /* ctrl sysfs entries */ 1393 static ssize_t omapfb_show_ctrl_name(struct device *dev, 1394 struct device_attribute *attr, char *buf) 1395 { 1396 struct omapfb_device *fbdev = dev_get_drvdata(dev); 1397 1398 return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); 1399 } 1400 1401 static struct device_attribute dev_attr_ctrl_name = 1402 __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); 1403 1404 static struct attribute *ctrl_attrs[] = { 1405 &dev_attr_ctrl_name.attr, 1406 NULL, 1407 }; 1408 1409 static const struct attribute_group ctrl_attr_grp = { 1410 .name = "ctrl", 1411 .attrs = ctrl_attrs, 1412 }; 1413 1414 static int omapfb_register_sysfs(struct omapfb_device *fbdev) 1415 { 1416 int r; 1417 1418 if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) 1419 goto fail0; 1420 1421 if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) 1422 goto fail1; 1423 1424 if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) 1425 goto fail2; 1426 1427 if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) 1428 goto fail3; 1429 1430 return 0; 1431 fail3: 1432 sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); 1433 fail2: 1434 device_remove_file(fbdev->dev, &dev_attr_caps_text); 1435 fail1: 1436 device_remove_file(fbdev->dev, &dev_attr_caps_num); 1437 fail0: 1438 dev_err(fbdev->dev, "unable to register sysfs interface\n"); 1439 return r; 1440 } 1441 1442 static void omapfb_unregister_sysfs(struct omapfb_device *fbdev) 1443 { 1444 sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); 1445 sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); 1446 device_remove_file(fbdev->dev, &dev_attr_caps_num); 1447 device_remove_file(fbdev->dev, &dev_attr_caps_text); 1448 } 1449 1450 /* 1451 * --------------------------------------------------------------------------- 1452 * LDM callbacks 1453 * --------------------------------------------------------------------------- 1454 */ 1455 /* Initialize system fb_info object and set the default video mode. 1456 * The frame buffer memory already allocated by lcddma_init 1457 */ 1458 static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) 1459 { 1460 struct fb_var_screeninfo *var = &info->var; 1461 struct fb_fix_screeninfo *fix = &info->fix; 1462 int r = 0; 1463 1464 info->fbops = &omapfb_ops; 1465 info->flags = FBINFO_FLAG_DEFAULT; 1466 1467 strncpy(fix->id, MODULE_NAME, sizeof(fix->id)); 1468 1469 info->pseudo_palette = fbdev->pseudo_palette; 1470 1471 var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; 1472 var->xres = def_vxres; 1473 var->yres = def_vyres; 1474 var->xres_virtual = def_vxres; 1475 var->yres_virtual = def_vyres; 1476 var->rotate = def_rotate; 1477 var->bits_per_pixel = fbdev->panel->bpp; 1478 1479 set_fb_var(info, var); 1480 set_fb_fix(info, 1); 1481 1482 r = fb_alloc_cmap(&info->cmap, 16, 0); 1483 if (r != 0) 1484 dev_err(fbdev->dev, "unable to allocate color map memory\n"); 1485 1486 return r; 1487 } 1488 1489 /* Release the fb_info object */ 1490 static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi) 1491 { 1492 fb_dealloc_cmap(&fbi->cmap); 1493 } 1494 1495 static void planes_cleanup(struct omapfb_device *fbdev) 1496 { 1497 int i; 1498 1499 for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 1500 if (fbdev->fb_info[i] == NULL) 1501 break; 1502 fbinfo_cleanup(fbdev, fbdev->fb_info[i]); 1503 framebuffer_release(fbdev->fb_info[i]); 1504 } 1505 } 1506 1507 static int planes_init(struct omapfb_device *fbdev) 1508 { 1509 struct fb_info *fbi; 1510 int i; 1511 int r; 1512 1513 for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 1514 struct omapfb_plane_struct *plane; 1515 fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), 1516 fbdev->dev); 1517 if (fbi == NULL) { 1518 dev_err(fbdev->dev, 1519 "unable to allocate memory for plane info\n"); 1520 planes_cleanup(fbdev); 1521 return -ENOMEM; 1522 } 1523 plane = fbi->par; 1524 plane->idx = i; 1525 plane->fbdev = fbdev; 1526 plane->info.mirror = def_mirror; 1527 fbdev->fb_info[i] = fbi; 1528 1529 if ((r = fbinfo_init(fbdev, fbi)) < 0) { 1530 framebuffer_release(fbi); 1531 planes_cleanup(fbdev); 1532 return r; 1533 } 1534 plane->info.out_width = fbi->var.xres; 1535 plane->info.out_height = fbi->var.yres; 1536 } 1537 return 0; 1538 } 1539 1540 /* 1541 * Free driver resources. Can be called to rollback an aborted initialization 1542 * sequence. 1543 */ 1544 static void omapfb_free_resources(struct omapfb_device *fbdev, int state) 1545 { 1546 int i; 1547 1548 switch (state) { 1549 case OMAPFB_ACTIVE: 1550 for (i = 0; i < fbdev->mem_desc.region_cnt; i++) 1551 unregister_framebuffer(fbdev->fb_info[i]); 1552 case 7: 1553 omapfb_unregister_sysfs(fbdev); 1554 case 6: 1555 if (fbdev->panel->disable) 1556 fbdev->panel->disable(fbdev->panel); 1557 case 5: 1558 omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED); 1559 case 4: 1560 planes_cleanup(fbdev); 1561 case 3: 1562 ctrl_cleanup(fbdev); 1563 case 2: 1564 if (fbdev->panel->cleanup) 1565 fbdev->panel->cleanup(fbdev->panel); 1566 case 1: 1567 dev_set_drvdata(fbdev->dev, NULL); 1568 kfree(fbdev); 1569 case 0: 1570 /* nothing to free */ 1571 break; 1572 default: 1573 BUG(); 1574 } 1575 } 1576 1577 static int omapfb_find_ctrl(struct omapfb_device *fbdev) 1578 { 1579 struct omapfb_platform_data *conf; 1580 char name[17]; 1581 int i; 1582 1583 conf = dev_get_platdata(fbdev->dev); 1584 1585 fbdev->ctrl = NULL; 1586 1587 strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1); 1588 name[sizeof(name) - 1] = '\0'; 1589 1590 if (strcmp(name, "internal") == 0) { 1591 fbdev->ctrl = fbdev->int_ctrl; 1592 return 0; 1593 } 1594 1595 for (i = 0; i < ARRAY_SIZE(ctrls); i++) { 1596 dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name); 1597 if (strcmp(ctrls[i]->name, name) == 0) { 1598 fbdev->ctrl = ctrls[i]; 1599 break; 1600 } 1601 } 1602 1603 if (fbdev->ctrl == NULL) { 1604 dev_dbg(fbdev->dev, "ctrl %s not supported\n", name); 1605 return -1; 1606 } 1607 1608 return 0; 1609 } 1610 1611 /* 1612 * Called by LDM binding to probe and attach a new device. 1613 * Initialization sequence: 1614 * 1. allocate system omapfb_device structure 1615 * 2. select controller type according to platform configuration 1616 * init LCD panel 1617 * 3. init LCD controller and LCD DMA 1618 * 4. init system fb_info structure for all planes 1619 * 5. setup video mode for first plane and enable it 1620 * 6. enable LCD panel 1621 * 7. register sysfs attributes 1622 * OMAPFB_ACTIVE: register system fb_info structure for all planes 1623 */ 1624 static int omapfb_do_probe(struct platform_device *pdev, 1625 struct lcd_panel *panel) 1626 { 1627 struct omapfb_device *fbdev = NULL; 1628 int init_state; 1629 unsigned long phz, hhz, vhz; 1630 unsigned long vram; 1631 int i; 1632 int r = 0; 1633 1634 init_state = 0; 1635 1636 if (pdev->num_resources != 0) { 1637 dev_err(&pdev->dev, "probed for an unknown device\n"); 1638 r = -ENODEV; 1639 goto cleanup; 1640 } 1641 1642 if (dev_get_platdata(&pdev->dev) == NULL) { 1643 dev_err(&pdev->dev, "missing platform data\n"); 1644 r = -ENOENT; 1645 goto cleanup; 1646 } 1647 1648 fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 1649 if (fbdev == NULL) { 1650 dev_err(&pdev->dev, 1651 "unable to allocate memory for device info\n"); 1652 r = -ENOMEM; 1653 goto cleanup; 1654 } 1655 init_state++; 1656 1657 fbdev->dev = &pdev->dev; 1658 fbdev->panel = panel; 1659 fbdev->dssdev = &omapdss_device; 1660 platform_set_drvdata(pdev, fbdev); 1661 1662 mutex_init(&fbdev->rqueue_mutex); 1663 1664 fbdev->int_ctrl = &omap1_int_ctrl; 1665 #ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 1666 fbdev->ext_if = &omap1_ext_if; 1667 #endif 1668 if (omapfb_find_ctrl(fbdev) < 0) { 1669 dev_err(fbdev->dev, 1670 "LCD controller not found, board not supported\n"); 1671 r = -ENODEV; 1672 goto cleanup; 1673 } 1674 1675 if (fbdev->panel->init) { 1676 r = fbdev->panel->init(fbdev->panel, fbdev); 1677 if (r) 1678 goto cleanup; 1679 } 1680 1681 pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); 1682 1683 def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res; 1684 def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res; 1685 1686 init_state++; 1687 1688 r = ctrl_init(fbdev); 1689 if (r) 1690 goto cleanup; 1691 if (fbdev->ctrl->mmap != NULL) 1692 omapfb_ops.fb_mmap = omapfb_mmap; 1693 init_state++; 1694 1695 r = planes_init(fbdev); 1696 if (r) 1697 goto cleanup; 1698 init_state++; 1699 1700 #ifdef CONFIG_FB_OMAP_DMA_TUNE 1701 /* Set DMA priority for EMIFF access to highest */ 1702 omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); 1703 #endif 1704 1705 r = ctrl_change_mode(fbdev->fb_info[0]); 1706 if (r) { 1707 dev_err(fbdev->dev, "mode setting failed\n"); 1708 goto cleanup; 1709 } 1710 1711 /* GFX plane is enabled by default */ 1712 r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); 1713 if (r) 1714 goto cleanup; 1715 1716 omapfb_set_update_mode(fbdev, manual_update ? 1717 OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE); 1718 init_state++; 1719 1720 if (fbdev->panel->enable) { 1721 r = fbdev->panel->enable(fbdev->panel); 1722 if (r) 1723 goto cleanup; 1724 } 1725 init_state++; 1726 1727 r = omapfb_register_sysfs(fbdev); 1728 if (r) 1729 goto cleanup; 1730 init_state++; 1731 1732 vram = 0; 1733 for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 1734 r = register_framebuffer(fbdev->fb_info[i]); 1735 if (r != 0) { 1736 dev_err(fbdev->dev, 1737 "registering framebuffer %d failed\n", i); 1738 goto cleanup; 1739 } 1740 vram += fbdev->mem_desc.region[i].size; 1741 } 1742 1743 fbdev->state = OMAPFB_ACTIVE; 1744 1745 panel = fbdev->panel; 1746 phz = panel->pixel_clock * 1000; 1747 hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw); 1748 vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw); 1749 1750 omapfb_dev = fbdev; 1751 1752 pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n", 1753 vram, fbdev->mem_desc.region_cnt); 1754 pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz " 1755 "vfreq %lu.%lu Hz\n", 1756 phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10); 1757 1758 return 0; 1759 1760 cleanup: 1761 omapfb_free_resources(fbdev, init_state); 1762 1763 return r; 1764 } 1765 1766 static int omapfb_probe(struct platform_device *pdev) 1767 { 1768 int r; 1769 1770 BUG_ON(fbdev_pdev != NULL); 1771 1772 r = platform_device_register(&omapdss_device); 1773 if (r) { 1774 dev_err(&pdev->dev, "can't register omapdss device\n"); 1775 return r; 1776 } 1777 1778 /* Delay actual initialization until the LCD is registered */ 1779 fbdev_pdev = pdev; 1780 if (fbdev_panel != NULL) 1781 omapfb_do_probe(fbdev_pdev, fbdev_panel); 1782 return 0; 1783 } 1784 1785 void omapfb_register_panel(struct lcd_panel *panel) 1786 { 1787 BUG_ON(fbdev_panel != NULL); 1788 1789 fbdev_panel = panel; 1790 if (fbdev_pdev != NULL) 1791 omapfb_do_probe(fbdev_pdev, fbdev_panel); 1792 } 1793 EXPORT_SYMBOL_GPL(omapfb_register_panel); 1794 1795 /* Called when the device is being detached from the driver */ 1796 static int omapfb_remove(struct platform_device *pdev) 1797 { 1798 struct omapfb_device *fbdev = platform_get_drvdata(pdev); 1799 enum omapfb_state saved_state = fbdev->state; 1800 1801 /* FIXME: wait till completion of pending events */ 1802 1803 fbdev->state = OMAPFB_DISABLED; 1804 omapfb_free_resources(fbdev, saved_state); 1805 1806 platform_device_unregister(&omapdss_device); 1807 fbdev->dssdev = NULL; 1808 1809 return 0; 1810 } 1811 1812 /* PM suspend */ 1813 static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) 1814 { 1815 struct omapfb_device *fbdev = platform_get_drvdata(pdev); 1816 1817 if (fbdev != NULL) 1818 omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]); 1819 return 0; 1820 } 1821 1822 /* PM resume */ 1823 static int omapfb_resume(struct platform_device *pdev) 1824 { 1825 struct omapfb_device *fbdev = platform_get_drvdata(pdev); 1826 1827 if (fbdev != NULL) 1828 omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]); 1829 return 0; 1830 } 1831 1832 static struct platform_driver omapfb_driver = { 1833 .probe = omapfb_probe, 1834 .remove = omapfb_remove, 1835 .suspend = omapfb_suspend, 1836 .resume = omapfb_resume, 1837 .driver = { 1838 .name = MODULE_NAME, 1839 }, 1840 }; 1841 1842 #ifndef MODULE 1843 1844 /* Process kernel command line parameters */ 1845 static int __init omapfb_setup(char *options) 1846 { 1847 char *this_opt = NULL; 1848 int r = 0; 1849 1850 pr_debug("omapfb: options %s\n", options); 1851 1852 if (!options || !*options) 1853 return 0; 1854 1855 while (!r && (this_opt = strsep(&options, ",")) != NULL) { 1856 if (!strncmp(this_opt, "accel", 5)) 1857 def_accel = 1; 1858 else if (!strncmp(this_opt, "vram:", 5)) { 1859 char *suffix; 1860 unsigned long vram; 1861 vram = (simple_strtoul(this_opt + 5, &suffix, 0)); 1862 switch (suffix[0]) { 1863 case '\0': 1864 break; 1865 case 'm': 1866 case 'M': 1867 vram *= 1024; 1868 /* Fall through */ 1869 case 'k': 1870 case 'K': 1871 vram *= 1024; 1872 break; 1873 default: 1874 pr_debug("omapfb: invalid vram suffix %c\n", 1875 suffix[0]); 1876 r = -1; 1877 } 1878 def_vram[def_vram_cnt++] = vram; 1879 } 1880 else if (!strncmp(this_opt, "vxres:", 6)) 1881 def_vxres = simple_strtoul(this_opt + 6, NULL, 0); 1882 else if (!strncmp(this_opt, "vyres:", 6)) 1883 def_vyres = simple_strtoul(this_opt + 6, NULL, 0); 1884 else if (!strncmp(this_opt, "rotate:", 7)) 1885 def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); 1886 else if (!strncmp(this_opt, "mirror:", 7)) 1887 def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); 1888 else if (!strncmp(this_opt, "manual_update", 13)) 1889 manual_update = 1; 1890 else { 1891 pr_debug("omapfb: invalid option\n"); 1892 r = -1; 1893 } 1894 } 1895 1896 return r; 1897 } 1898 1899 #endif 1900 1901 /* Register both the driver and the device */ 1902 static int __init omapfb_init(void) 1903 { 1904 #ifndef MODULE 1905 char *option; 1906 1907 if (fb_get_options("omapfb", &option)) 1908 return -ENODEV; 1909 omapfb_setup(option); 1910 #endif 1911 /* Register the driver with LDM */ 1912 if (platform_driver_register(&omapfb_driver)) { 1913 pr_debug("failed to register omapfb driver\n"); 1914 return -ENODEV; 1915 } 1916 1917 return 0; 1918 } 1919 1920 static void __exit omapfb_cleanup(void) 1921 { 1922 platform_driver_unregister(&omapfb_driver); 1923 } 1924 1925 module_param_named(accel, def_accel, uint, 0664); 1926 module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664); 1927 module_param_named(vxres, def_vxres, long, 0664); 1928 module_param_named(vyres, def_vyres, long, 0664); 1929 module_param_named(rotate, def_rotate, uint, 0664); 1930 module_param_named(mirror, def_mirror, uint, 0664); 1931 module_param_named(manual_update, manual_update, bool, 0664); 1932 1933 module_init(omapfb_init); 1934 module_exit(omapfb_cleanup); 1935 1936 MODULE_DESCRIPTION("TI OMAP framebuffer driver"); 1937 MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>"); 1938 MODULE_LICENSE("GPL"); 1939