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