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

Configure Feed

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

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