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