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

Configure Feed

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

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