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