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