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

OMAP: DSS2: omapfb driver

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>

+3813 -3
+46 -1
arch/arm/plat-omap/fb.c
··· 55 55 .num_resources = 0, 56 56 }; 57 57 58 + void omapfb_set_platform_data(struct omapfb_platform_data *data) 59 + { 60 + } 61 + 58 62 static inline int ranges_overlap(unsigned long start1, unsigned long size1, 59 63 unsigned long start2, unsigned long size2) 60 64 { ··· 331 327 332 328 arch_initcall(omap_init_fb); 333 329 334 - #else 330 + #elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) 331 + 332 + static u64 omap_fb_dma_mask = ~(u32)0; 333 + static struct omapfb_platform_data omapfb_config; 334 + 335 + static struct platform_device omap_fb_device = { 336 + .name = "omapfb", 337 + .id = -1, 338 + .dev = { 339 + .dma_mask = &omap_fb_dma_mask, 340 + .coherent_dma_mask = ~(u32)0, 341 + .platform_data = &omapfb_config, 342 + }, 343 + .num_resources = 0, 344 + }; 345 + 346 + void omapfb_set_platform_data(struct omapfb_platform_data *data) 347 + { 348 + omapfb_config = *data; 349 + } 350 + 351 + static inline int omap_init_fb(void) 352 + { 353 + return platform_device_register(&omap_fb_device); 354 + } 355 + 356 + arch_initcall(omap_init_fb); 335 357 336 358 void omapfb_reserve_sdram(void) {} 337 359 unsigned long omapfb_reserve_sram(unsigned long sram_pstart, ··· 369 339 return 0; 370 340 } 371 341 342 + #else 343 + 344 + void omapfb_set_platform_data(struct omapfb_platform_data *data) 345 + { 346 + } 347 + 348 + void omapfb_reserve_sdram(void) {} 349 + unsigned long omapfb_reserve_sram(unsigned long sram_pstart, 350 + unsigned long sram_vstart, 351 + unsigned long sram_size, 352 + unsigned long start_avail, 353 + unsigned long size_avail) 354 + { 355 + return 0; 356 + } 372 357 373 358 #endif
+3 -2
drivers/video/omap/Kconfig
··· 1 1 config FB_OMAP 2 2 tristate "OMAP frame buffer support (EXPERIMENTAL)" 3 - depends on FB && ARCH_OMAP 3 + depends on FB && ARCH_OMAP && (OMAP2_DSS = "n") 4 + 4 5 select FB_CFB_FILLRECT 5 6 select FB_CFB_COPYAREA 6 7 select FB_CFB_IMAGEBLIT ··· 73 72 74 73 config FB_OMAP_BOOTLOADER_INIT 75 74 bool "Check bootloader initialization" 76 - depends on FB_OMAP 75 + depends on FB_OMAP || FB_OMAP2 77 76 help 78 77 Say Y here if you want to enable checking if the bootloader has 79 78 already initialized the display controller. In this case the
+1
drivers/video/omap2/Kconfig
··· 5 5 bool 6 6 7 7 source "drivers/video/omap2/dss/Kconfig" 8 + source "drivers/video/omap2/omapfb/Kconfig"
+1
drivers/video/omap2/Makefile
··· 2 2 obj-$(CONFIG_OMAP2_VRFB) += vrfb.o 3 3 4 4 obj-y += dss/ 5 + obj-y += omapfb/
+37
drivers/video/omap2/omapfb/Kconfig
··· 1 + menuconfig FB_OMAP2 2 + tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)" 3 + depends on FB && OMAP2_DSS 4 + 5 + select OMAP2_VRAM 6 + select OMAP2_VRFB 7 + select FB_CFB_FILLRECT 8 + select FB_CFB_COPYAREA 9 + select FB_CFB_IMAGEBLIT 10 + help 11 + Frame buffer driver for OMAP2/3 based boards. 12 + 13 + config FB_OMAP2_DEBUG_SUPPORT 14 + bool "Debug support for OMAP2/3 FB" 15 + default y 16 + depends on FB_OMAP2 17 + help 18 + Support for debug output. You have to enable the actual printing 19 + with debug module parameter. 20 + 21 + config FB_OMAP2_FORCE_AUTO_UPDATE 22 + bool "Force main display to automatic update mode" 23 + depends on FB_OMAP2 24 + help 25 + Forces main display to automatic update mode (if possible), 26 + and also enables tearsync (if possible). By default 27 + displays that support manual update are started in manual 28 + update mode. 29 + 30 + config FB_OMAP2_NUM_FBS 31 + int "Number of framebuffers" 32 + range 1 10 33 + default 3 34 + depends on FB_OMAP2 35 + help 36 + Select the number of framebuffers created. OMAP2/3 has 3 overlays 37 + so normally this would be 3.
+2
drivers/video/omap2/omapfb/Makefile
··· 1 + obj-$(CONFIG_FB_OMAP2) += omapfb.o 2 + omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
+755
drivers/video/omap2/omapfb/omapfb-ioctl.c
··· 1 + /* 2 + * linux/drivers/video/omap2/omapfb-ioctl.c 3 + * 4 + * Copyright (C) 2008 Nokia Corporation 5 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 6 + * 7 + * Some code and ideas taken from drivers/video/omap/ driver 8 + * by Imre Deak. 9 + * 10 + * This program is free software; you can redistribute it and/or modify it 11 + * under the terms of the GNU General Public License version 2 as published by 12 + * the Free Software Foundation. 13 + * 14 + * This program is distributed in the hope that it will be useful, but WITHOUT 15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 + * more details. 18 + * 19 + * You should have received a copy of the GNU General Public License along with 20 + * this program. If not, see <http://www.gnu.org/licenses/>. 21 + */ 22 + 23 + #include <linux/fb.h> 24 + #include <linux/device.h> 25 + #include <linux/uaccess.h> 26 + #include <linux/platform_device.h> 27 + #include <linux/mm.h> 28 + #include <linux/omapfb.h> 29 + #include <linux/vmalloc.h> 30 + 31 + #include <plat/display.h> 32 + #include <plat/vrfb.h> 33 + #include <plat/vram.h> 34 + 35 + #include "omapfb.h" 36 + 37 + static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 38 + { 39 + struct omapfb_info *ofbi = FB2OFB(fbi); 40 + struct omapfb2_device *fbdev = ofbi->fbdev; 41 + struct omap_overlay *ovl; 42 + struct omap_overlay_info info; 43 + int r = 0; 44 + 45 + DBG("omapfb_setup_plane\n"); 46 + 47 + if (ofbi->num_overlays != 1) { 48 + r = -EINVAL; 49 + goto out; 50 + } 51 + 52 + /* XXX uses only the first overlay */ 53 + ovl = ofbi->overlays[0]; 54 + 55 + if (pi->enabled && !ofbi->region.size) { 56 + /* 57 + * This plane's memory was freed, can't enable it 58 + * until it's reallocated. 59 + */ 60 + r = -EINVAL; 61 + goto out; 62 + } 63 + 64 + ovl->get_overlay_info(ovl, &info); 65 + 66 + info.pos_x = pi->pos_x; 67 + info.pos_y = pi->pos_y; 68 + info.out_width = pi->out_width; 69 + info.out_height = pi->out_height; 70 + info.enabled = pi->enabled; 71 + 72 + r = ovl->set_overlay_info(ovl, &info); 73 + if (r) 74 + goto out; 75 + 76 + if (ovl->manager) { 77 + r = ovl->manager->apply(ovl->manager); 78 + if (r) 79 + goto out; 80 + } 81 + 82 + out: 83 + if (r) 84 + dev_err(fbdev->dev, "setup_plane failed\n"); 85 + return r; 86 + } 87 + 88 + static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 89 + { 90 + struct omapfb_info *ofbi = FB2OFB(fbi); 91 + 92 + if (ofbi->num_overlays != 1) { 93 + memset(pi, 0, sizeof(*pi)); 94 + } else { 95 + struct omap_overlay_info *ovli; 96 + struct omap_overlay *ovl; 97 + 98 + ovl = ofbi->overlays[0]; 99 + ovli = &ovl->info; 100 + 101 + pi->pos_x = ovli->pos_x; 102 + pi->pos_y = ovli->pos_y; 103 + pi->enabled = ovli->enabled; 104 + pi->channel_out = 0; /* xxx */ 105 + pi->mirror = 0; 106 + pi->out_width = ovli->out_width; 107 + pi->out_height = ovli->out_height; 108 + } 109 + 110 + return 0; 111 + } 112 + 113 + static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 114 + { 115 + struct omapfb_info *ofbi = FB2OFB(fbi); 116 + struct omapfb2_device *fbdev = ofbi->fbdev; 117 + struct omapfb2_mem_region *rg; 118 + int r, i; 119 + size_t size; 120 + 121 + if (mi->type > OMAPFB_MEMTYPE_MAX) 122 + return -EINVAL; 123 + 124 + size = PAGE_ALIGN(mi->size); 125 + 126 + rg = &ofbi->region; 127 + 128 + for (i = 0; i < ofbi->num_overlays; i++) { 129 + if (ofbi->overlays[i]->info.enabled) 130 + return -EBUSY; 131 + } 132 + 133 + if (rg->size != size || rg->type != mi->type) { 134 + r = omapfb_realloc_fbmem(fbi, size, mi->type); 135 + if (r) { 136 + dev_err(fbdev->dev, "realloc fbmem failed\n"); 137 + return r; 138 + } 139 + } 140 + 141 + return 0; 142 + } 143 + 144 + static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 145 + { 146 + struct omapfb_info *ofbi = FB2OFB(fbi); 147 + struct omapfb2_mem_region *rg; 148 + 149 + rg = &ofbi->region; 150 + memset(mi, 0, sizeof(*mi)); 151 + 152 + mi->size = rg->size; 153 + mi->type = rg->type; 154 + 155 + return 0; 156 + } 157 + 158 + static int omapfb_update_window_nolock(struct fb_info *fbi, 159 + u32 x, u32 y, u32 w, u32 h) 160 + { 161 + struct omap_dss_device *display = fb2display(fbi); 162 + u16 dw, dh; 163 + 164 + if (!display) 165 + return 0; 166 + 167 + if (w == 0 || h == 0) 168 + return 0; 169 + 170 + display->get_resolution(display, &dw, &dh); 171 + 172 + if (x + w > dw || y + h > dh) 173 + return -EINVAL; 174 + 175 + return display->update(display, x, y, w, h); 176 + } 177 + 178 + /* This function is exported for SGX driver use */ 179 + int omapfb_update_window(struct fb_info *fbi, 180 + u32 x, u32 y, u32 w, u32 h) 181 + { 182 + struct omapfb_info *ofbi = FB2OFB(fbi); 183 + struct omapfb2_device *fbdev = ofbi->fbdev; 184 + int r; 185 + 186 + omapfb_lock(fbdev); 187 + lock_fb_info(fbi); 188 + 189 + r = omapfb_update_window_nolock(fbi, x, y, w, h); 190 + 191 + unlock_fb_info(fbi); 192 + omapfb_unlock(fbdev); 193 + 194 + return r; 195 + } 196 + EXPORT_SYMBOL(omapfb_update_window); 197 + 198 + static int omapfb_set_update_mode(struct fb_info *fbi, 199 + enum omapfb_update_mode mode) 200 + { 201 + struct omap_dss_device *display = fb2display(fbi); 202 + enum omap_dss_update_mode um; 203 + int r; 204 + 205 + if (!display || !display->set_update_mode) 206 + return -EINVAL; 207 + 208 + switch (mode) { 209 + case OMAPFB_UPDATE_DISABLED: 210 + um = OMAP_DSS_UPDATE_DISABLED; 211 + break; 212 + 213 + case OMAPFB_AUTO_UPDATE: 214 + um = OMAP_DSS_UPDATE_AUTO; 215 + break; 216 + 217 + case OMAPFB_MANUAL_UPDATE: 218 + um = OMAP_DSS_UPDATE_MANUAL; 219 + break; 220 + 221 + default: 222 + return -EINVAL; 223 + } 224 + 225 + r = display->set_update_mode(display, um); 226 + 227 + return r; 228 + } 229 + 230 + static int omapfb_get_update_mode(struct fb_info *fbi, 231 + enum omapfb_update_mode *mode) 232 + { 233 + struct omap_dss_device *display = fb2display(fbi); 234 + enum omap_dss_update_mode m; 235 + 236 + if (!display || !display->get_update_mode) 237 + return -EINVAL; 238 + 239 + m = display->get_update_mode(display); 240 + 241 + switch (m) { 242 + case OMAP_DSS_UPDATE_DISABLED: 243 + *mode = OMAPFB_UPDATE_DISABLED; 244 + break; 245 + case OMAP_DSS_UPDATE_AUTO: 246 + *mode = OMAPFB_AUTO_UPDATE; 247 + break; 248 + case OMAP_DSS_UPDATE_MANUAL: 249 + *mode = OMAPFB_MANUAL_UPDATE; 250 + break; 251 + default: 252 + BUG(); 253 + } 254 + 255 + return 0; 256 + } 257 + 258 + /* XXX this color key handling is a hack... */ 259 + static struct omapfb_color_key omapfb_color_keys[2]; 260 + 261 + static int _omapfb_set_color_key(struct omap_overlay_manager *mgr, 262 + struct omapfb_color_key *ck) 263 + { 264 + struct omap_overlay_manager_info info; 265 + enum omap_dss_trans_key_type kt; 266 + int r; 267 + 268 + mgr->get_manager_info(mgr, &info); 269 + 270 + if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) { 271 + info.trans_enabled = false; 272 + omapfb_color_keys[mgr->id] = *ck; 273 + 274 + r = mgr->set_manager_info(mgr, &info); 275 + if (r) 276 + return r; 277 + 278 + r = mgr->apply(mgr); 279 + 280 + return r; 281 + } 282 + 283 + switch (ck->key_type) { 284 + case OMAPFB_COLOR_KEY_GFX_DST: 285 + kt = OMAP_DSS_COLOR_KEY_GFX_DST; 286 + break; 287 + case OMAPFB_COLOR_KEY_VID_SRC: 288 + kt = OMAP_DSS_COLOR_KEY_VID_SRC; 289 + break; 290 + default: 291 + return -EINVAL; 292 + } 293 + 294 + info.default_color = ck->background; 295 + info.trans_key = ck->trans_key; 296 + info.trans_key_type = kt; 297 + info.trans_enabled = true; 298 + 299 + omapfb_color_keys[mgr->id] = *ck; 300 + 301 + r = mgr->set_manager_info(mgr, &info); 302 + if (r) 303 + return r; 304 + 305 + r = mgr->apply(mgr); 306 + 307 + return r; 308 + } 309 + 310 + static int omapfb_set_color_key(struct fb_info *fbi, 311 + struct omapfb_color_key *ck) 312 + { 313 + struct omapfb_info *ofbi = FB2OFB(fbi); 314 + struct omapfb2_device *fbdev = ofbi->fbdev; 315 + int r; 316 + int i; 317 + struct omap_overlay_manager *mgr = NULL; 318 + 319 + omapfb_lock(fbdev); 320 + 321 + for (i = 0; i < ofbi->num_overlays; i++) { 322 + if (ofbi->overlays[i]->manager) { 323 + mgr = ofbi->overlays[i]->manager; 324 + break; 325 + } 326 + } 327 + 328 + if (!mgr) { 329 + r = -EINVAL; 330 + goto err; 331 + } 332 + 333 + r = _omapfb_set_color_key(mgr, ck); 334 + err: 335 + omapfb_unlock(fbdev); 336 + 337 + return r; 338 + } 339 + 340 + static int omapfb_get_color_key(struct fb_info *fbi, 341 + struct omapfb_color_key *ck) 342 + { 343 + struct omapfb_info *ofbi = FB2OFB(fbi); 344 + struct omapfb2_device *fbdev = ofbi->fbdev; 345 + struct omap_overlay_manager *mgr = NULL; 346 + int r = 0; 347 + int i; 348 + 349 + omapfb_lock(fbdev); 350 + 351 + for (i = 0; i < ofbi->num_overlays; i++) { 352 + if (ofbi->overlays[i]->manager) { 353 + mgr = ofbi->overlays[i]->manager; 354 + break; 355 + } 356 + } 357 + 358 + if (!mgr) { 359 + r = -EINVAL; 360 + goto err; 361 + } 362 + 363 + *ck = omapfb_color_keys[mgr->id]; 364 + err: 365 + omapfb_unlock(fbdev); 366 + 367 + return r; 368 + } 369 + 370 + static int omapfb_memory_read(struct fb_info *fbi, 371 + struct omapfb_memory_read *mr) 372 + { 373 + struct omap_dss_device *display = fb2display(fbi); 374 + void *buf; 375 + int r; 376 + 377 + if (!display || !display->memory_read) 378 + return -ENOENT; 379 + 380 + if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size)) 381 + return -EFAULT; 382 + 383 + if (mr->w * mr->h * 3 > mr->buffer_size) 384 + return -EINVAL; 385 + 386 + buf = vmalloc(mr->buffer_size); 387 + if (!buf) { 388 + DBG("vmalloc failed\n"); 389 + return -ENOMEM; 390 + } 391 + 392 + r = display->memory_read(display, buf, mr->buffer_size, 393 + mr->x, mr->y, mr->w, mr->h); 394 + 395 + if (r > 0) { 396 + if (copy_to_user(mr->buffer, buf, mr->buffer_size)) 397 + r = -EFAULT; 398 + } 399 + 400 + vfree(buf); 401 + 402 + return r; 403 + } 404 + 405 + static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev, 406 + struct omapfb_ovl_colormode *mode) 407 + { 408 + int ovl_idx = mode->overlay_idx; 409 + int mode_idx = mode->mode_idx; 410 + struct omap_overlay *ovl; 411 + enum omap_color_mode supported_modes; 412 + struct fb_var_screeninfo var; 413 + int i; 414 + 415 + if (ovl_idx >= fbdev->num_overlays) 416 + return -ENODEV; 417 + ovl = fbdev->overlays[ovl_idx]; 418 + supported_modes = ovl->supported_modes; 419 + 420 + mode_idx = mode->mode_idx; 421 + 422 + for (i = 0; i < sizeof(supported_modes) * 8; i++) { 423 + if (!(supported_modes & (1 << i))) 424 + continue; 425 + /* 426 + * It's possible that the FB doesn't support a mode 427 + * that is supported by the overlay, so call the 428 + * following here. 429 + */ 430 + if (dss_mode_to_fb_mode(1 << i, &var) < 0) 431 + continue; 432 + 433 + mode_idx--; 434 + if (mode_idx < 0) 435 + break; 436 + } 437 + 438 + if (i == sizeof(supported_modes) * 8) 439 + return -ENOENT; 440 + 441 + mode->bits_per_pixel = var.bits_per_pixel; 442 + mode->nonstd = var.nonstd; 443 + mode->red = var.red; 444 + mode->green = var.green; 445 + mode->blue = var.blue; 446 + mode->transp = var.transp; 447 + 448 + return 0; 449 + } 450 + 451 + static int omapfb_wait_for_go(struct fb_info *fbi) 452 + { 453 + struct omapfb_info *ofbi = FB2OFB(fbi); 454 + int r = 0; 455 + int i; 456 + 457 + for (i = 0; i < ofbi->num_overlays; ++i) { 458 + struct omap_overlay *ovl = ofbi->overlays[i]; 459 + r = ovl->wait_for_go(ovl); 460 + if (r) 461 + break; 462 + } 463 + 464 + return r; 465 + } 466 + 467 + int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) 468 + { 469 + struct omapfb_info *ofbi = FB2OFB(fbi); 470 + struct omapfb2_device *fbdev = ofbi->fbdev; 471 + struct omap_dss_device *display = fb2display(fbi); 472 + 473 + union { 474 + struct omapfb_update_window_old uwnd_o; 475 + struct omapfb_update_window uwnd; 476 + struct omapfb_plane_info plane_info; 477 + struct omapfb_caps caps; 478 + struct omapfb_mem_info mem_info; 479 + struct omapfb_color_key color_key; 480 + struct omapfb_ovl_colormode ovl_colormode; 481 + enum omapfb_update_mode update_mode; 482 + int test_num; 483 + struct omapfb_memory_read memory_read; 484 + struct omapfb_vram_info vram_info; 485 + struct omapfb_tearsync_info tearsync_info; 486 + } p; 487 + 488 + int r = 0; 489 + 490 + switch (cmd) { 491 + case OMAPFB_SYNC_GFX: 492 + DBG("ioctl SYNC_GFX\n"); 493 + if (!display || !display->sync) { 494 + /* DSS1 never returns an error here, so we neither */ 495 + /*r = -EINVAL;*/ 496 + break; 497 + } 498 + 499 + r = display->sync(display); 500 + break; 501 + 502 + case OMAPFB_UPDATE_WINDOW_OLD: 503 + DBG("ioctl UPDATE_WINDOW_OLD\n"); 504 + if (!display || !display->update) { 505 + r = -EINVAL; 506 + break; 507 + } 508 + 509 + if (copy_from_user(&p.uwnd_o, 510 + (void __user *)arg, 511 + sizeof(p.uwnd_o))) { 512 + r = -EFAULT; 513 + break; 514 + } 515 + 516 + r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, 517 + p.uwnd_o.width, p.uwnd_o.height); 518 + break; 519 + 520 + case OMAPFB_UPDATE_WINDOW: 521 + DBG("ioctl UPDATE_WINDOW\n"); 522 + if (!display || !display->update) { 523 + r = -EINVAL; 524 + break; 525 + } 526 + 527 + if (copy_from_user(&p.uwnd, (void __user *)arg, 528 + sizeof(p.uwnd))) { 529 + r = -EFAULT; 530 + break; 531 + } 532 + 533 + r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, 534 + p.uwnd.width, p.uwnd.height); 535 + break; 536 + 537 + case OMAPFB_SETUP_PLANE: 538 + DBG("ioctl SETUP_PLANE\n"); 539 + if (copy_from_user(&p.plane_info, (void __user *)arg, 540 + sizeof(p.plane_info))) 541 + r = -EFAULT; 542 + else 543 + r = omapfb_setup_plane(fbi, &p.plane_info); 544 + break; 545 + 546 + case OMAPFB_QUERY_PLANE: 547 + DBG("ioctl QUERY_PLANE\n"); 548 + r = omapfb_query_plane(fbi, &p.plane_info); 549 + if (r < 0) 550 + break; 551 + if (copy_to_user((void __user *)arg, &p.plane_info, 552 + sizeof(p.plane_info))) 553 + r = -EFAULT; 554 + break; 555 + 556 + case OMAPFB_SETUP_MEM: 557 + DBG("ioctl SETUP_MEM\n"); 558 + if (copy_from_user(&p.mem_info, (void __user *)arg, 559 + sizeof(p.mem_info))) 560 + r = -EFAULT; 561 + else 562 + r = omapfb_setup_mem(fbi, &p.mem_info); 563 + break; 564 + 565 + case OMAPFB_QUERY_MEM: 566 + DBG("ioctl QUERY_MEM\n"); 567 + r = omapfb_query_mem(fbi, &p.mem_info); 568 + if (r < 0) 569 + break; 570 + if (copy_to_user((void __user *)arg, &p.mem_info, 571 + sizeof(p.mem_info))) 572 + r = -EFAULT; 573 + break; 574 + 575 + case OMAPFB_GET_CAPS: 576 + DBG("ioctl GET_CAPS\n"); 577 + if (!display) { 578 + r = -EINVAL; 579 + break; 580 + } 581 + 582 + memset(&p.caps, 0, sizeof(p.caps)); 583 + if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) 584 + p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE; 585 + if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM) 586 + p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC; 587 + 588 + if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) 589 + r = -EFAULT; 590 + break; 591 + 592 + case OMAPFB_GET_OVERLAY_COLORMODE: 593 + DBG("ioctl GET_OVERLAY_COLORMODE\n"); 594 + if (copy_from_user(&p.ovl_colormode, (void __user *)arg, 595 + sizeof(p.ovl_colormode))) { 596 + r = -EFAULT; 597 + break; 598 + } 599 + r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode); 600 + if (r < 0) 601 + break; 602 + if (copy_to_user((void __user *)arg, &p.ovl_colormode, 603 + sizeof(p.ovl_colormode))) 604 + r = -EFAULT; 605 + break; 606 + 607 + case OMAPFB_SET_UPDATE_MODE: 608 + DBG("ioctl SET_UPDATE_MODE\n"); 609 + if (get_user(p.update_mode, (int __user *)arg)) 610 + r = -EFAULT; 611 + else 612 + r = omapfb_set_update_mode(fbi, p.update_mode); 613 + break; 614 + 615 + case OMAPFB_GET_UPDATE_MODE: 616 + DBG("ioctl GET_UPDATE_MODE\n"); 617 + r = omapfb_get_update_mode(fbi, &p.update_mode); 618 + if (r) 619 + break; 620 + if (put_user(p.update_mode, 621 + (enum omapfb_update_mode __user *)arg)) 622 + r = -EFAULT; 623 + break; 624 + 625 + case OMAPFB_SET_COLOR_KEY: 626 + DBG("ioctl SET_COLOR_KEY\n"); 627 + if (copy_from_user(&p.color_key, (void __user *)arg, 628 + sizeof(p.color_key))) 629 + r = -EFAULT; 630 + else 631 + r = omapfb_set_color_key(fbi, &p.color_key); 632 + break; 633 + 634 + case OMAPFB_GET_COLOR_KEY: 635 + DBG("ioctl GET_COLOR_KEY\n"); 636 + r = omapfb_get_color_key(fbi, &p.color_key); 637 + if (r) 638 + break; 639 + if (copy_to_user((void __user *)arg, &p.color_key, 640 + sizeof(p.color_key))) 641 + r = -EFAULT; 642 + break; 643 + 644 + case OMAPFB_WAITFORVSYNC: 645 + DBG("ioctl WAITFORVSYNC\n"); 646 + if (!display) { 647 + r = -EINVAL; 648 + break; 649 + } 650 + 651 + r = display->wait_vsync(display); 652 + break; 653 + 654 + case OMAPFB_WAITFORGO: 655 + DBG("ioctl WAITFORGO\n"); 656 + if (!display) { 657 + r = -EINVAL; 658 + break; 659 + } 660 + 661 + r = omapfb_wait_for_go(fbi); 662 + break; 663 + 664 + /* LCD and CTRL tests do the same thing for backward 665 + * compatibility */ 666 + case OMAPFB_LCD_TEST: 667 + DBG("ioctl LCD_TEST\n"); 668 + if (get_user(p.test_num, (int __user *)arg)) { 669 + r = -EFAULT; 670 + break; 671 + } 672 + if (!display || !display->run_test) { 673 + r = -EINVAL; 674 + break; 675 + } 676 + 677 + r = display->run_test(display, p.test_num); 678 + 679 + break; 680 + 681 + case OMAPFB_CTRL_TEST: 682 + DBG("ioctl CTRL_TEST\n"); 683 + if (get_user(p.test_num, (int __user *)arg)) { 684 + r = -EFAULT; 685 + break; 686 + } 687 + if (!display || !display->run_test) { 688 + r = -EINVAL; 689 + break; 690 + } 691 + 692 + r = display->run_test(display, p.test_num); 693 + 694 + break; 695 + 696 + case OMAPFB_MEMORY_READ: 697 + DBG("ioctl MEMORY_READ\n"); 698 + 699 + if (copy_from_user(&p.memory_read, (void __user *)arg, 700 + sizeof(p.memory_read))) { 701 + r = -EFAULT; 702 + break; 703 + } 704 + 705 + r = omapfb_memory_read(fbi, &p.memory_read); 706 + 707 + break; 708 + 709 + case OMAPFB_GET_VRAM_INFO: { 710 + unsigned long vram, free, largest; 711 + 712 + DBG("ioctl GET_VRAM_INFO\n"); 713 + 714 + omap_vram_get_info(&vram, &free, &largest); 715 + p.vram_info.total = vram; 716 + p.vram_info.free = free; 717 + p.vram_info.largest_free_block = largest; 718 + 719 + if (copy_to_user((void __user *)arg, &p.vram_info, 720 + sizeof(p.vram_info))) 721 + r = -EFAULT; 722 + break; 723 + } 724 + 725 + case OMAPFB_SET_TEARSYNC: { 726 + DBG("ioctl SET_TEARSYNC\n"); 727 + 728 + if (copy_from_user(&p.tearsync_info, (void __user *)arg, 729 + sizeof(p.tearsync_info))) { 730 + r = -EFAULT; 731 + break; 732 + } 733 + 734 + if (!display->enable_te) { 735 + r = -ENODEV; 736 + break; 737 + } 738 + 739 + r = display->enable_te(display, !!p.tearsync_info.enabled); 740 + 741 + break; 742 + } 743 + 744 + default: 745 + dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); 746 + r = -EINVAL; 747 + } 748 + 749 + if (r < 0) 750 + DBG("ioctl failed: %d\n", r); 751 + 752 + return r; 753 + } 754 + 755 +
+2261
drivers/video/omap2/omapfb/omapfb-main.c
··· 1 + /* 2 + * linux/drivers/video/omap2/omapfb-main.c 3 + * 4 + * Copyright (C) 2008 Nokia Corporation 5 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 6 + * 7 + * Some code and ideas taken from drivers/video/omap/ driver 8 + * by Imre Deak. 9 + * 10 + * This program is free software; you can redistribute it and/or modify it 11 + * under the terms of the GNU General Public License version 2 as published by 12 + * the Free Software Foundation. 13 + * 14 + * This program is distributed in the hope that it will be useful, but WITHOUT 15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 + * more details. 18 + * 19 + * You should have received a copy of the GNU General Public License along with 20 + * this program. If not, see <http://www.gnu.org/licenses/>. 21 + */ 22 + 23 + #include <linux/module.h> 24 + #include <linux/delay.h> 25 + #include <linux/fb.h> 26 + #include <linux/dma-mapping.h> 27 + #include <linux/vmalloc.h> 28 + #include <linux/device.h> 29 + #include <linux/platform_device.h> 30 + #include <linux/omapfb.h> 31 + 32 + #include <plat/display.h> 33 + #include <plat/vram.h> 34 + #include <plat/vrfb.h> 35 + 36 + #include "omapfb.h" 37 + 38 + #define MODULE_NAME "omapfb" 39 + 40 + #define OMAPFB_PLANE_XRES_MIN 8 41 + #define OMAPFB_PLANE_YRES_MIN 8 42 + 43 + static char *def_mode; 44 + static char *def_vram; 45 + static int def_vrfb; 46 + static int def_rotate; 47 + static int def_mirror; 48 + 49 + #ifdef DEBUG 50 + unsigned int omapfb_debug; 51 + module_param_named(debug, omapfb_debug, bool, 0644); 52 + static unsigned int omapfb_test_pattern; 53 + module_param_named(test, omapfb_test_pattern, bool, 0644); 54 + #endif 55 + 56 + static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi); 57 + 58 + #ifdef DEBUG 59 + static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color) 60 + { 61 + struct fb_var_screeninfo *var = &fbi->var; 62 + struct fb_fix_screeninfo *fix = &fbi->fix; 63 + void __iomem *addr = fbi->screen_base; 64 + const unsigned bytespp = var->bits_per_pixel >> 3; 65 + const unsigned line_len = fix->line_length / bytespp; 66 + 67 + int r = (color >> 16) & 0xff; 68 + int g = (color >> 8) & 0xff; 69 + int b = (color >> 0) & 0xff; 70 + 71 + if (var->bits_per_pixel == 16) { 72 + u16 __iomem *p = (u16 __iomem *)addr; 73 + p += y * line_len + x; 74 + 75 + r = r * 32 / 256; 76 + g = g * 64 / 256; 77 + b = b * 32 / 256; 78 + 79 + __raw_writew((r << 11) | (g << 5) | (b << 0), p); 80 + } else if (var->bits_per_pixel == 24) { 81 + u8 __iomem *p = (u8 __iomem *)addr; 82 + p += (y * line_len + x) * 3; 83 + 84 + __raw_writeb(b, p + 0); 85 + __raw_writeb(g, p + 1); 86 + __raw_writeb(r, p + 2); 87 + } else if (var->bits_per_pixel == 32) { 88 + u32 __iomem *p = (u32 __iomem *)addr; 89 + p += y * line_len + x; 90 + __raw_writel(color, p); 91 + } 92 + } 93 + 94 + static void fill_fb(struct fb_info *fbi) 95 + { 96 + struct fb_var_screeninfo *var = &fbi->var; 97 + const short w = var->xres_virtual; 98 + const short h = var->yres_virtual; 99 + void __iomem *addr = fbi->screen_base; 100 + int y, x; 101 + 102 + if (!addr) 103 + return; 104 + 105 + DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length); 106 + 107 + for (y = 0; y < h; y++) { 108 + for (x = 0; x < w; x++) { 109 + if (x < 20 && y < 20) 110 + draw_pixel(fbi, x, y, 0xffffff); 111 + else if (x < 20 && (y > 20 && y < h - 20)) 112 + draw_pixel(fbi, x, y, 0xff); 113 + else if (y < 20 && (x > 20 && x < w - 20)) 114 + draw_pixel(fbi, x, y, 0xff00); 115 + else if (x > w - 20 && (y > 20 && y < h - 20)) 116 + draw_pixel(fbi, x, y, 0xff0000); 117 + else if (y > h - 20 && (x > 20 && x < w - 20)) 118 + draw_pixel(fbi, x, y, 0xffff00); 119 + else if (x == 20 || x == w - 20 || 120 + y == 20 || y == h - 20) 121 + draw_pixel(fbi, x, y, 0xffffff); 122 + else if (x == y || w - x == h - y) 123 + draw_pixel(fbi, x, y, 0xff00ff); 124 + else if (w - x == y || x == h - y) 125 + draw_pixel(fbi, x, y, 0x00ffff); 126 + else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) { 127 + int t = x * 3 / w; 128 + unsigned r = 0, g = 0, b = 0; 129 + unsigned c; 130 + if (var->bits_per_pixel == 16) { 131 + if (t == 0) 132 + b = (y % 32) * 256 / 32; 133 + else if (t == 1) 134 + g = (y % 64) * 256 / 64; 135 + else if (t == 2) 136 + r = (y % 32) * 256 / 32; 137 + } else { 138 + if (t == 0) 139 + b = (y % 256); 140 + else if (t == 1) 141 + g = (y % 256); 142 + else if (t == 2) 143 + r = (y % 256); 144 + } 145 + c = (r << 16) | (g << 8) | (b << 0); 146 + draw_pixel(fbi, x, y, c); 147 + } else { 148 + draw_pixel(fbi, x, y, 0); 149 + } 150 + } 151 + } 152 + } 153 + #endif 154 + 155 + static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot) 156 + { 157 + struct vrfb *vrfb = &ofbi->region.vrfb; 158 + unsigned offset; 159 + 160 + switch (rot) { 161 + case FB_ROTATE_UR: 162 + offset = 0; 163 + break; 164 + case FB_ROTATE_CW: 165 + offset = vrfb->yoffset; 166 + break; 167 + case FB_ROTATE_UD: 168 + offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset; 169 + break; 170 + case FB_ROTATE_CCW: 171 + offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN; 172 + break; 173 + default: 174 + BUG(); 175 + } 176 + 177 + offset *= vrfb->bytespp; 178 + 179 + return offset; 180 + } 181 + 182 + static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot) 183 + { 184 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 185 + return ofbi->region.vrfb.paddr[rot] 186 + + omapfb_get_vrfb_offset(ofbi, rot); 187 + } else { 188 + return ofbi->region.paddr; 189 + } 190 + } 191 + 192 + static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi) 193 + { 194 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 195 + return ofbi->region.vrfb.paddr[0]; 196 + else 197 + return ofbi->region.paddr; 198 + } 199 + 200 + static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi) 201 + { 202 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 203 + return ofbi->region.vrfb.vaddr[0]; 204 + else 205 + return ofbi->region.vaddr; 206 + } 207 + 208 + static struct omapfb_colormode omapfb_colormodes[] = { 209 + { 210 + .dssmode = OMAP_DSS_COLOR_UYVY, 211 + .bits_per_pixel = 16, 212 + .nonstd = OMAPFB_COLOR_YUV422, 213 + }, { 214 + .dssmode = OMAP_DSS_COLOR_YUV2, 215 + .bits_per_pixel = 16, 216 + .nonstd = OMAPFB_COLOR_YUY422, 217 + }, { 218 + .dssmode = OMAP_DSS_COLOR_ARGB16, 219 + .bits_per_pixel = 16, 220 + .red = { .length = 4, .offset = 8, .msb_right = 0 }, 221 + .green = { .length = 4, .offset = 4, .msb_right = 0 }, 222 + .blue = { .length = 4, .offset = 0, .msb_right = 0 }, 223 + .transp = { .length = 4, .offset = 12, .msb_right = 0 }, 224 + }, { 225 + .dssmode = OMAP_DSS_COLOR_RGB16, 226 + .bits_per_pixel = 16, 227 + .red = { .length = 5, .offset = 11, .msb_right = 0 }, 228 + .green = { .length = 6, .offset = 5, .msb_right = 0 }, 229 + .blue = { .length = 5, .offset = 0, .msb_right = 0 }, 230 + .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 231 + }, { 232 + .dssmode = OMAP_DSS_COLOR_RGB24P, 233 + .bits_per_pixel = 24, 234 + .red = { .length = 8, .offset = 16, .msb_right = 0 }, 235 + .green = { .length = 8, .offset = 8, .msb_right = 0 }, 236 + .blue = { .length = 8, .offset = 0, .msb_right = 0 }, 237 + .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 238 + }, { 239 + .dssmode = OMAP_DSS_COLOR_RGB24U, 240 + .bits_per_pixel = 32, 241 + .red = { .length = 8, .offset = 16, .msb_right = 0 }, 242 + .green = { .length = 8, .offset = 8, .msb_right = 0 }, 243 + .blue = { .length = 8, .offset = 0, .msb_right = 0 }, 244 + .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 245 + }, { 246 + .dssmode = OMAP_DSS_COLOR_ARGB32, 247 + .bits_per_pixel = 32, 248 + .red = { .length = 8, .offset = 16, .msb_right = 0 }, 249 + .green = { .length = 8, .offset = 8, .msb_right = 0 }, 250 + .blue = { .length = 8, .offset = 0, .msb_right = 0 }, 251 + .transp = { .length = 8, .offset = 24, .msb_right = 0 }, 252 + }, { 253 + .dssmode = OMAP_DSS_COLOR_RGBA32, 254 + .bits_per_pixel = 32, 255 + .red = { .length = 8, .offset = 24, .msb_right = 0 }, 256 + .green = { .length = 8, .offset = 16, .msb_right = 0 }, 257 + .blue = { .length = 8, .offset = 8, .msb_right = 0 }, 258 + .transp = { .length = 8, .offset = 0, .msb_right = 0 }, 259 + }, { 260 + .dssmode = OMAP_DSS_COLOR_RGBX32, 261 + .bits_per_pixel = 32, 262 + .red = { .length = 8, .offset = 24, .msb_right = 0 }, 263 + .green = { .length = 8, .offset = 16, .msb_right = 0 }, 264 + .blue = { .length = 8, .offset = 8, .msb_right = 0 }, 265 + .transp = { .length = 0, .offset = 0, .msb_right = 0 }, 266 + }, 267 + }; 268 + 269 + static bool cmp_var_to_colormode(struct fb_var_screeninfo *var, 270 + struct omapfb_colormode *color) 271 + { 272 + bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2) 273 + { 274 + return f1->length == f2->length && 275 + f1->offset == f2->offset && 276 + f1->msb_right == f2->msb_right; 277 + } 278 + 279 + if (var->bits_per_pixel == 0 || 280 + var->red.length == 0 || 281 + var->blue.length == 0 || 282 + var->green.length == 0) 283 + return 0; 284 + 285 + return var->bits_per_pixel == color->bits_per_pixel && 286 + cmp_component(&var->red, &color->red) && 287 + cmp_component(&var->green, &color->green) && 288 + cmp_component(&var->blue, &color->blue) && 289 + cmp_component(&var->transp, &color->transp); 290 + } 291 + 292 + static void assign_colormode_to_var(struct fb_var_screeninfo *var, 293 + struct omapfb_colormode *color) 294 + { 295 + var->bits_per_pixel = color->bits_per_pixel; 296 + var->nonstd = color->nonstd; 297 + var->red = color->red; 298 + var->green = color->green; 299 + var->blue = color->blue; 300 + var->transp = color->transp; 301 + } 302 + 303 + static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var, 304 + enum omap_color_mode *mode) 305 + { 306 + enum omap_color_mode dssmode; 307 + int i; 308 + 309 + /* first match with nonstd field */ 310 + if (var->nonstd) { 311 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 312 + struct omapfb_colormode *m = &omapfb_colormodes[i]; 313 + if (var->nonstd == m->nonstd) { 314 + assign_colormode_to_var(var, m); 315 + *mode = m->dssmode; 316 + return 0; 317 + } 318 + } 319 + 320 + return -EINVAL; 321 + } 322 + 323 + /* then try exact match of bpp and colors */ 324 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 325 + struct omapfb_colormode *m = &omapfb_colormodes[i]; 326 + if (cmp_var_to_colormode(var, m)) { 327 + assign_colormode_to_var(var, m); 328 + *mode = m->dssmode; 329 + return 0; 330 + } 331 + } 332 + 333 + /* match with bpp if user has not filled color fields 334 + * properly */ 335 + switch (var->bits_per_pixel) { 336 + case 1: 337 + dssmode = OMAP_DSS_COLOR_CLUT1; 338 + break; 339 + case 2: 340 + dssmode = OMAP_DSS_COLOR_CLUT2; 341 + break; 342 + case 4: 343 + dssmode = OMAP_DSS_COLOR_CLUT4; 344 + break; 345 + case 8: 346 + dssmode = OMAP_DSS_COLOR_CLUT8; 347 + break; 348 + case 12: 349 + dssmode = OMAP_DSS_COLOR_RGB12U; 350 + break; 351 + case 16: 352 + dssmode = OMAP_DSS_COLOR_RGB16; 353 + break; 354 + case 24: 355 + dssmode = OMAP_DSS_COLOR_RGB24P; 356 + break; 357 + case 32: 358 + dssmode = OMAP_DSS_COLOR_RGB24U; 359 + break; 360 + default: 361 + return -EINVAL; 362 + } 363 + 364 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 365 + struct omapfb_colormode *m = &omapfb_colormodes[i]; 366 + if (dssmode == m->dssmode) { 367 + assign_colormode_to_var(var, m); 368 + *mode = m->dssmode; 369 + return 0; 370 + } 371 + } 372 + 373 + return -EINVAL; 374 + } 375 + 376 + static int check_fb_res_bounds(struct fb_var_screeninfo *var) 377 + { 378 + int xres_min = OMAPFB_PLANE_XRES_MIN; 379 + int xres_max = 2048; 380 + int yres_min = OMAPFB_PLANE_YRES_MIN; 381 + int yres_max = 2048; 382 + 383 + /* XXX: some applications seem to set virtual res to 0. */ 384 + if (var->xres_virtual == 0) 385 + var->xres_virtual = var->xres; 386 + 387 + if (var->yres_virtual == 0) 388 + var->yres_virtual = var->yres; 389 + 390 + if (var->xres_virtual < xres_min || var->yres_virtual < yres_min) 391 + return -EINVAL; 392 + 393 + if (var->xres < xres_min) 394 + var->xres = xres_min; 395 + if (var->yres < yres_min) 396 + var->yres = yres_min; 397 + if (var->xres > xres_max) 398 + var->xres = xres_max; 399 + if (var->yres > yres_max) 400 + var->yres = yres_max; 401 + 402 + if (var->xres > var->xres_virtual) 403 + var->xres = var->xres_virtual; 404 + if (var->yres > var->yres_virtual) 405 + var->yres = var->yres_virtual; 406 + 407 + return 0; 408 + } 409 + 410 + static void shrink_height(unsigned long max_frame_size, 411 + struct fb_var_screeninfo *var) 412 + { 413 + DBG("can't fit FB into memory, reducing y\n"); 414 + var->yres_virtual = max_frame_size / 415 + (var->xres_virtual * var->bits_per_pixel >> 3); 416 + 417 + if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN) 418 + var->yres_virtual = OMAPFB_PLANE_YRES_MIN; 419 + 420 + if (var->yres > var->yres_virtual) 421 + var->yres = var->yres_virtual; 422 + } 423 + 424 + static void shrink_width(unsigned long max_frame_size, 425 + struct fb_var_screeninfo *var) 426 + { 427 + DBG("can't fit FB into memory, reducing x\n"); 428 + var->xres_virtual = max_frame_size / var->yres_virtual / 429 + (var->bits_per_pixel >> 3); 430 + 431 + if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN) 432 + var->xres_virtual = OMAPFB_PLANE_XRES_MIN; 433 + 434 + if (var->xres > var->xres_virtual) 435 + var->xres = var->xres_virtual; 436 + } 437 + 438 + static int check_vrfb_fb_size(unsigned long region_size, 439 + const struct fb_var_screeninfo *var) 440 + { 441 + unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual, 442 + var->yres_virtual, var->bits_per_pixel >> 3); 443 + 444 + return min_phys_size > region_size ? -EINVAL : 0; 445 + } 446 + 447 + static int check_fb_size(const struct omapfb_info *ofbi, 448 + struct fb_var_screeninfo *var) 449 + { 450 + unsigned long max_frame_size = ofbi->region.size; 451 + int bytespp = var->bits_per_pixel >> 3; 452 + unsigned long line_size = var->xres_virtual * bytespp; 453 + 454 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 455 + /* One needs to check for both VRFB and OMAPFB limitations. */ 456 + if (check_vrfb_fb_size(max_frame_size, var)) 457 + shrink_height(omap_vrfb_max_height( 458 + max_frame_size, var->xres_virtual, bytespp) * 459 + line_size, var); 460 + 461 + if (check_vrfb_fb_size(max_frame_size, var)) { 462 + DBG("cannot fit FB to memory\n"); 463 + return -EINVAL; 464 + } 465 + 466 + return 0; 467 + } 468 + 469 + DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size); 470 + 471 + if (line_size * var->yres_virtual > max_frame_size) 472 + shrink_height(max_frame_size, var); 473 + 474 + if (line_size * var->yres_virtual > max_frame_size) { 475 + shrink_width(max_frame_size, var); 476 + line_size = var->xres_virtual * bytespp; 477 + } 478 + 479 + if (line_size * var->yres_virtual > max_frame_size) { 480 + DBG("cannot fit FB to memory\n"); 481 + return -EINVAL; 482 + } 483 + 484 + return 0; 485 + } 486 + 487 + /* 488 + * Consider if VRFB assisted rotation is in use and if the virtual space for 489 + * the zero degree view needs to be mapped. The need for mapping also acts as 490 + * the trigger for setting up the hardware on the context in question. This 491 + * ensures that one does not attempt to access the virtual view before the 492 + * hardware is serving the address translations. 493 + */ 494 + static int setup_vrfb_rotation(struct fb_info *fbi) 495 + { 496 + struct omapfb_info *ofbi = FB2OFB(fbi); 497 + struct omapfb2_mem_region *rg = &ofbi->region; 498 + struct vrfb *vrfb = &rg->vrfb; 499 + struct fb_var_screeninfo *var = &fbi->var; 500 + struct fb_fix_screeninfo *fix = &fbi->fix; 501 + unsigned bytespp; 502 + bool yuv_mode; 503 + enum omap_color_mode mode; 504 + int r; 505 + bool reconf; 506 + 507 + if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB) 508 + return 0; 509 + 510 + DBG("setup_vrfb_rotation\n"); 511 + 512 + r = fb_mode_to_dss_mode(var, &mode); 513 + if (r) 514 + return r; 515 + 516 + bytespp = var->bits_per_pixel >> 3; 517 + 518 + yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY; 519 + 520 + /* We need to reconfigure VRFB if the resolution changes, if yuv mode 521 + * is enabled/disabled, or if bytes per pixel changes */ 522 + 523 + /* XXX we shouldn't allow this when framebuffer is mmapped */ 524 + 525 + reconf = false; 526 + 527 + if (yuv_mode != vrfb->yuv_mode) 528 + reconf = true; 529 + else if (bytespp != vrfb->bytespp) 530 + reconf = true; 531 + else if (vrfb->xres != var->xres_virtual || 532 + vrfb->yres != var->yres_virtual) 533 + reconf = true; 534 + 535 + if (vrfb->vaddr[0] && reconf) { 536 + fbi->screen_base = NULL; 537 + fix->smem_start = 0; 538 + fix->smem_len = 0; 539 + iounmap(vrfb->vaddr[0]); 540 + vrfb->vaddr[0] = NULL; 541 + DBG("setup_vrfb_rotation: reset fb\n"); 542 + } 543 + 544 + if (vrfb->vaddr[0]) 545 + return 0; 546 + 547 + omap_vrfb_setup(&rg->vrfb, rg->paddr, 548 + var->xres_virtual, 549 + var->yres_virtual, 550 + bytespp, yuv_mode); 551 + 552 + /* Now one can ioremap the 0 angle view */ 553 + r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0); 554 + if (r) 555 + return r; 556 + 557 + /* used by open/write in fbmem.c */ 558 + fbi->screen_base = ofbi->region.vrfb.vaddr[0]; 559 + 560 + fix->smem_start = ofbi->region.vrfb.paddr[0]; 561 + 562 + switch (var->nonstd) { 563 + case OMAPFB_COLOR_YUV422: 564 + case OMAPFB_COLOR_YUY422: 565 + fix->line_length = 566 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2; 567 + break; 568 + default: 569 + fix->line_length = 570 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3; 571 + break; 572 + } 573 + 574 + fix->smem_len = var->yres_virtual * fix->line_length; 575 + 576 + return 0; 577 + } 578 + 579 + int dss_mode_to_fb_mode(enum omap_color_mode dssmode, 580 + struct fb_var_screeninfo *var) 581 + { 582 + int i; 583 + 584 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) { 585 + struct omapfb_colormode *mode = &omapfb_colormodes[i]; 586 + if (dssmode == mode->dssmode) { 587 + assign_colormode_to_var(var, mode); 588 + return 0; 589 + } 590 + } 591 + return -ENOENT; 592 + } 593 + 594 + void set_fb_fix(struct fb_info *fbi) 595 + { 596 + struct fb_fix_screeninfo *fix = &fbi->fix; 597 + struct fb_var_screeninfo *var = &fbi->var; 598 + struct omapfb_info *ofbi = FB2OFB(fbi); 599 + struct omapfb2_mem_region *rg = &ofbi->region; 600 + 601 + DBG("set_fb_fix\n"); 602 + 603 + /* used by open/write in fbmem.c */ 604 + fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi); 605 + 606 + /* used by mmap in fbmem.c */ 607 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 608 + switch (var->nonstd) { 609 + case OMAPFB_COLOR_YUV422: 610 + case OMAPFB_COLOR_YUY422: 611 + fix->line_length = 612 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2; 613 + break; 614 + default: 615 + fix->line_length = 616 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3; 617 + break; 618 + } 619 + 620 + fix->smem_len = var->yres_virtual * fix->line_length; 621 + } else { 622 + fix->line_length = 623 + (var->xres_virtual * var->bits_per_pixel) >> 3; 624 + fix->smem_len = rg->size; 625 + } 626 + 627 + fix->smem_start = omapfb_get_region_paddr(ofbi); 628 + 629 + fix->type = FB_TYPE_PACKED_PIXELS; 630 + 631 + if (var->nonstd) 632 + fix->visual = FB_VISUAL_PSEUDOCOLOR; 633 + else { 634 + switch (var->bits_per_pixel) { 635 + case 32: 636 + case 24: 637 + case 16: 638 + case 12: 639 + fix->visual = FB_VISUAL_TRUECOLOR; 640 + /* 12bpp is stored in 16 bits */ 641 + break; 642 + case 1: 643 + case 2: 644 + case 4: 645 + case 8: 646 + fix->visual = FB_VISUAL_PSEUDOCOLOR; 647 + break; 648 + } 649 + } 650 + 651 + fix->accel = FB_ACCEL_NONE; 652 + 653 + fix->xpanstep = 1; 654 + fix->ypanstep = 1; 655 + } 656 + 657 + /* check new var and possibly modify it to be ok */ 658 + int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) 659 + { 660 + struct omapfb_info *ofbi = FB2OFB(fbi); 661 + struct omap_dss_device *display = fb2display(fbi); 662 + enum omap_color_mode mode = 0; 663 + int i; 664 + int r; 665 + 666 + DBG("check_fb_var %d\n", ofbi->id); 667 + 668 + if (ofbi->region.size == 0) 669 + return 0; 670 + 671 + r = fb_mode_to_dss_mode(var, &mode); 672 + if (r) { 673 + DBG("cannot convert var to omap dss mode\n"); 674 + return r; 675 + } 676 + 677 + for (i = 0; i < ofbi->num_overlays; ++i) { 678 + if ((ofbi->overlays[i]->supported_modes & mode) == 0) { 679 + DBG("invalid mode\n"); 680 + return -EINVAL; 681 + } 682 + } 683 + 684 + if (var->rotate < 0 || var->rotate > 3) 685 + return -EINVAL; 686 + 687 + if (check_fb_res_bounds(var)) 688 + return -EINVAL; 689 + 690 + if (check_fb_size(ofbi, var)) 691 + return -EINVAL; 692 + 693 + if (var->xres + var->xoffset > var->xres_virtual) 694 + var->xoffset = var->xres_virtual - var->xres; 695 + if (var->yres + var->yoffset > var->yres_virtual) 696 + var->yoffset = var->yres_virtual - var->yres; 697 + 698 + DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n", 699 + var->xres, var->yres, 700 + var->xres_virtual, var->yres_virtual); 701 + 702 + var->height = -1; 703 + var->width = -1; 704 + var->grayscale = 0; 705 + 706 + if (display && display->get_timings) { 707 + struct omap_video_timings timings; 708 + display->get_timings(display, &timings); 709 + 710 + /* pixclock in ps, the rest in pixclock */ 711 + var->pixclock = timings.pixel_clock != 0 ? 712 + KHZ2PICOS(timings.pixel_clock) : 713 + 0; 714 + var->left_margin = timings.hfp; 715 + var->right_margin = timings.hbp; 716 + var->upper_margin = timings.vfp; 717 + var->lower_margin = timings.vbp; 718 + var->hsync_len = timings.hsw; 719 + var->vsync_len = timings.vsw; 720 + } else { 721 + var->pixclock = 0; 722 + var->left_margin = 0; 723 + var->right_margin = 0; 724 + var->upper_margin = 0; 725 + var->lower_margin = 0; 726 + var->hsync_len = 0; 727 + var->vsync_len = 0; 728 + } 729 + 730 + /* TODO: get these from panel->config */ 731 + var->vmode = FB_VMODE_NONINTERLACED; 732 + var->sync = 0; 733 + 734 + return 0; 735 + } 736 + 737 + /* 738 + * --------------------------------------------------------------------------- 739 + * fbdev framework callbacks 740 + * --------------------------------------------------------------------------- 741 + */ 742 + static int omapfb_open(struct fb_info *fbi, int user) 743 + { 744 + return 0; 745 + } 746 + 747 + static int omapfb_release(struct fb_info *fbi, int user) 748 + { 749 + #if 0 750 + struct omapfb_info *ofbi = FB2OFB(fbi); 751 + struct omapfb2_device *fbdev = ofbi->fbdev; 752 + struct omap_dss_device *display = fb2display(fbi); 753 + 754 + DBG("Closing fb with plane index %d\n", ofbi->id); 755 + 756 + omapfb_lock(fbdev); 757 + 758 + if (display && display->get_update_mode && display->update) { 759 + /* XXX this update should be removed, I think. But it's 760 + * good for debugging */ 761 + if (display->get_update_mode(display) == 762 + OMAP_DSS_UPDATE_MANUAL) { 763 + u16 w, h; 764 + 765 + if (display->sync) 766 + display->sync(display); 767 + 768 + display->get_resolution(display, &w, &h); 769 + display->update(display, 0, 0, w, h); 770 + } 771 + } 772 + 773 + if (display && display->sync) 774 + display->sync(display); 775 + 776 + omapfb_unlock(fbdev); 777 + #endif 778 + return 0; 779 + } 780 + 781 + static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var, 782 + struct fb_fix_screeninfo *fix, int rotation) 783 + { 784 + unsigned offset; 785 + 786 + offset = var->yoffset * fix->line_length + 787 + var->xoffset * (var->bits_per_pixel >> 3); 788 + 789 + return offset; 790 + } 791 + 792 + static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var, 793 + struct fb_fix_screeninfo *fix, int rotation) 794 + { 795 + unsigned offset; 796 + 797 + if (rotation == FB_ROTATE_UD) 798 + offset = (var->yres_virtual - var->yres) * 799 + fix->line_length; 800 + else if (rotation == FB_ROTATE_CW) 801 + offset = (var->yres_virtual - var->yres) * 802 + (var->bits_per_pixel >> 3); 803 + else 804 + offset = 0; 805 + 806 + if (rotation == FB_ROTATE_UR) 807 + offset += var->yoffset * fix->line_length + 808 + var->xoffset * (var->bits_per_pixel >> 3); 809 + else if (rotation == FB_ROTATE_UD) 810 + offset -= var->yoffset * fix->line_length + 811 + var->xoffset * (var->bits_per_pixel >> 3); 812 + else if (rotation == FB_ROTATE_CW) 813 + offset -= var->xoffset * fix->line_length + 814 + var->yoffset * (var->bits_per_pixel >> 3); 815 + else if (rotation == FB_ROTATE_CCW) 816 + offset += var->xoffset * fix->line_length + 817 + var->yoffset * (var->bits_per_pixel >> 3); 818 + 819 + return offset; 820 + } 821 + 822 + 823 + /* setup overlay according to the fb */ 824 + static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, 825 + u16 posx, u16 posy, u16 outw, u16 outh) 826 + { 827 + int r = 0; 828 + struct omapfb_info *ofbi = FB2OFB(fbi); 829 + struct fb_var_screeninfo *var = &fbi->var; 830 + struct fb_fix_screeninfo *fix = &fbi->fix; 831 + enum omap_color_mode mode = 0; 832 + int offset; 833 + u32 data_start_p; 834 + void __iomem *data_start_v; 835 + struct omap_overlay_info info; 836 + int xres, yres; 837 + int screen_width; 838 + int mirror; 839 + int rotation = var->rotate; 840 + int i; 841 + 842 + for (i = 0; i < ofbi->num_overlays; i++) { 843 + if (ovl != ofbi->overlays[i]) 844 + continue; 845 + 846 + rotation = (rotation + ofbi->rotation[i]) % 4; 847 + break; 848 + } 849 + 850 + DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id, 851 + posx, posy, outw, outh); 852 + 853 + if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) { 854 + xres = var->yres; 855 + yres = var->xres; 856 + } else { 857 + xres = var->xres; 858 + yres = var->yres; 859 + } 860 + 861 + 862 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 863 + data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); 864 + data_start_v = NULL; 865 + } else { 866 + data_start_p = omapfb_get_region_paddr(ofbi); 867 + data_start_v = omapfb_get_region_vaddr(ofbi); 868 + } 869 + 870 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 871 + offset = calc_rotation_offset_vrfb(var, fix, rotation); 872 + else 873 + offset = calc_rotation_offset_dma(var, fix, rotation); 874 + 875 + data_start_p += offset; 876 + data_start_v += offset; 877 + 878 + if (offset) 879 + DBG("offset %d, %d = %d\n", 880 + var->xoffset, var->yoffset, offset); 881 + 882 + DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); 883 + 884 + r = fb_mode_to_dss_mode(var, &mode); 885 + if (r) { 886 + DBG("fb_mode_to_dss_mode failed"); 887 + goto err; 888 + } 889 + 890 + switch (var->nonstd) { 891 + case OMAPFB_COLOR_YUV422: 892 + case OMAPFB_COLOR_YUY422: 893 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 894 + screen_width = fix->line_length 895 + / (var->bits_per_pixel >> 2); 896 + break; 897 + } 898 + default: 899 + screen_width = fix->line_length / (var->bits_per_pixel >> 3); 900 + break; 901 + } 902 + 903 + ovl->get_overlay_info(ovl, &info); 904 + 905 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) 906 + mirror = 0; 907 + else 908 + mirror = ofbi->mirror; 909 + 910 + info.paddr = data_start_p; 911 + info.vaddr = data_start_v; 912 + info.screen_width = screen_width; 913 + info.width = xres; 914 + info.height = yres; 915 + info.color_mode = mode; 916 + info.rotation_type = ofbi->rotation_type; 917 + info.rotation = rotation; 918 + info.mirror = mirror; 919 + 920 + info.pos_x = posx; 921 + info.pos_y = posy; 922 + info.out_width = outw; 923 + info.out_height = outh; 924 + 925 + r = ovl->set_overlay_info(ovl, &info); 926 + if (r) { 927 + DBG("ovl->setup_overlay_info failed\n"); 928 + goto err; 929 + } 930 + 931 + return 0; 932 + 933 + err: 934 + DBG("setup_overlay failed\n"); 935 + return r; 936 + } 937 + 938 + /* apply var to the overlay */ 939 + int omapfb_apply_changes(struct fb_info *fbi, int init) 940 + { 941 + int r = 0; 942 + struct omapfb_info *ofbi = FB2OFB(fbi); 943 + struct fb_var_screeninfo *var = &fbi->var; 944 + struct omap_overlay *ovl; 945 + u16 posx, posy; 946 + u16 outw, outh; 947 + int i; 948 + 949 + #ifdef DEBUG 950 + if (omapfb_test_pattern) 951 + fill_fb(fbi); 952 + #endif 953 + 954 + for (i = 0; i < ofbi->num_overlays; i++) { 955 + ovl = ofbi->overlays[i]; 956 + 957 + DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); 958 + 959 + if (ofbi->region.size == 0) { 960 + /* the fb is not available. disable the overlay */ 961 + omapfb_overlay_enable(ovl, 0); 962 + if (!init && ovl->manager) 963 + ovl->manager->apply(ovl->manager); 964 + continue; 965 + } 966 + 967 + if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { 968 + int rotation = (var->rotate + ofbi->rotation[i]) % 4; 969 + if (rotation == FB_ROTATE_CW || 970 + rotation == FB_ROTATE_CCW) { 971 + outw = var->yres; 972 + outh = var->xres; 973 + } else { 974 + outw = var->xres; 975 + outh = var->yres; 976 + } 977 + } else { 978 + outw = ovl->info.out_width; 979 + outh = ovl->info.out_height; 980 + } 981 + 982 + if (init) { 983 + posx = 0; 984 + posy = 0; 985 + } else { 986 + posx = ovl->info.pos_x; 987 + posy = ovl->info.pos_y; 988 + } 989 + 990 + r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); 991 + if (r) 992 + goto err; 993 + 994 + if (!init && ovl->manager) 995 + ovl->manager->apply(ovl->manager); 996 + } 997 + return 0; 998 + err: 999 + DBG("apply_changes failed\n"); 1000 + return r; 1001 + } 1002 + 1003 + /* checks var and eventually tweaks it to something supported, 1004 + * DO NOT MODIFY PAR */ 1005 + static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) 1006 + { 1007 + int r; 1008 + 1009 + DBG("check_var(%d)\n", FB2OFB(fbi)->id); 1010 + 1011 + r = check_fb_var(fbi, var); 1012 + 1013 + return r; 1014 + } 1015 + 1016 + /* set the video mode according to info->var */ 1017 + static int omapfb_set_par(struct fb_info *fbi) 1018 + { 1019 + int r; 1020 + 1021 + DBG("set_par(%d)\n", FB2OFB(fbi)->id); 1022 + 1023 + set_fb_fix(fbi); 1024 + 1025 + r = setup_vrfb_rotation(fbi); 1026 + if (r) 1027 + return r; 1028 + 1029 + r = omapfb_apply_changes(fbi, 0); 1030 + 1031 + return r; 1032 + } 1033 + 1034 + static int omapfb_pan_display(struct fb_var_screeninfo *var, 1035 + struct fb_info *fbi) 1036 + { 1037 + struct fb_var_screeninfo new_var; 1038 + int r; 1039 + 1040 + DBG("pan_display(%d)\n", FB2OFB(fbi)->id); 1041 + 1042 + if (var->xoffset == fbi->var.xoffset && 1043 + var->yoffset == fbi->var.yoffset) 1044 + return 0; 1045 + 1046 + new_var = fbi->var; 1047 + new_var.xoffset = var->xoffset; 1048 + new_var.yoffset = var->yoffset; 1049 + 1050 + fbi->var = new_var; 1051 + 1052 + r = omapfb_apply_changes(fbi, 0); 1053 + 1054 + return r; 1055 + } 1056 + 1057 + static void mmap_user_open(struct vm_area_struct *vma) 1058 + { 1059 + struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; 1060 + 1061 + atomic_inc(&ofbi->map_count); 1062 + } 1063 + 1064 + static void mmap_user_close(struct vm_area_struct *vma) 1065 + { 1066 + struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; 1067 + 1068 + atomic_dec(&ofbi->map_count); 1069 + } 1070 + 1071 + static struct vm_operations_struct mmap_user_ops = { 1072 + .open = mmap_user_open, 1073 + .close = mmap_user_close, 1074 + }; 1075 + 1076 + static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) 1077 + { 1078 + struct omapfb_info *ofbi = FB2OFB(fbi); 1079 + struct fb_fix_screeninfo *fix = &fbi->fix; 1080 + unsigned long off; 1081 + unsigned long start; 1082 + u32 len; 1083 + 1084 + if (vma->vm_end - vma->vm_start == 0) 1085 + return 0; 1086 + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1087 + return -EINVAL; 1088 + off = vma->vm_pgoff << PAGE_SHIFT; 1089 + 1090 + start = omapfb_get_region_paddr(ofbi); 1091 + len = fix->smem_len; 1092 + if (off >= len) 1093 + return -EINVAL; 1094 + if ((vma->vm_end - vma->vm_start + off) > len) 1095 + return -EINVAL; 1096 + 1097 + off += start; 1098 + 1099 + DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off); 1100 + 1101 + vma->vm_pgoff = off >> PAGE_SHIFT; 1102 + vma->vm_flags |= VM_IO | VM_RESERVED; 1103 + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 1104 + vma->vm_ops = &mmap_user_ops; 1105 + vma->vm_private_data = ofbi; 1106 + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, 1107 + vma->vm_end - vma->vm_start, vma->vm_page_prot)) 1108 + return -EAGAIN; 1109 + /* vm_ops.open won't be called for mmap itself. */ 1110 + atomic_inc(&ofbi->map_count); 1111 + return 0; 1112 + } 1113 + 1114 + /* Store a single color palette entry into a pseudo palette or the hardware 1115 + * palette if one is available. For now we support only 16bpp and thus store 1116 + * the entry only to the pseudo palette. 1117 + */ 1118 + static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, 1119 + u_int blue, u_int transp, int update_hw_pal) 1120 + { 1121 + /*struct omapfb_info *ofbi = FB2OFB(fbi);*/ 1122 + /*struct omapfb2_device *fbdev = ofbi->fbdev;*/ 1123 + struct fb_var_screeninfo *var = &fbi->var; 1124 + int r = 0; 1125 + 1126 + enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */ 1127 + 1128 + /*switch (plane->color_mode) {*/ 1129 + switch (mode) { 1130 + case OMAPFB_COLOR_YUV422: 1131 + case OMAPFB_COLOR_YUV420: 1132 + case OMAPFB_COLOR_YUY422: 1133 + r = -EINVAL; 1134 + break; 1135 + case OMAPFB_COLOR_CLUT_8BPP: 1136 + case OMAPFB_COLOR_CLUT_4BPP: 1137 + case OMAPFB_COLOR_CLUT_2BPP: 1138 + case OMAPFB_COLOR_CLUT_1BPP: 1139 + /* 1140 + if (fbdev->ctrl->setcolreg) 1141 + r = fbdev->ctrl->setcolreg(regno, red, green, blue, 1142 + transp, update_hw_pal); 1143 + */ 1144 + /* Fallthrough */ 1145 + r = -EINVAL; 1146 + break; 1147 + case OMAPFB_COLOR_RGB565: 1148 + case OMAPFB_COLOR_RGB444: 1149 + case OMAPFB_COLOR_RGB24P: 1150 + case OMAPFB_COLOR_RGB24U: 1151 + if (r != 0) 1152 + break; 1153 + 1154 + if (regno < 0) { 1155 + r = -EINVAL; 1156 + break; 1157 + } 1158 + 1159 + if (regno < 16) { 1160 + u16 pal; 1161 + pal = ((red >> (16 - var->red.length)) << 1162 + var->red.offset) | 1163 + ((green >> (16 - var->green.length)) << 1164 + var->green.offset) | 1165 + (blue >> (16 - var->blue.length)); 1166 + ((u32 *)(fbi->pseudo_palette))[regno] = pal; 1167 + } 1168 + break; 1169 + default: 1170 + BUG(); 1171 + } 1172 + return r; 1173 + } 1174 + 1175 + static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 1176 + u_int transp, struct fb_info *info) 1177 + { 1178 + DBG("setcolreg\n"); 1179 + 1180 + return _setcolreg(info, regno, red, green, blue, transp, 1); 1181 + } 1182 + 1183 + static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) 1184 + { 1185 + int count, index, r; 1186 + u16 *red, *green, *blue, *transp; 1187 + u16 trans = 0xffff; 1188 + 1189 + DBG("setcmap\n"); 1190 + 1191 + red = cmap->red; 1192 + green = cmap->green; 1193 + blue = cmap->blue; 1194 + transp = cmap->transp; 1195 + index = cmap->start; 1196 + 1197 + for (count = 0; count < cmap->len; count++) { 1198 + if (transp) 1199 + trans = *transp++; 1200 + r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, 1201 + count == cmap->len - 1); 1202 + if (r != 0) 1203 + return r; 1204 + } 1205 + 1206 + return 0; 1207 + } 1208 + 1209 + static int omapfb_blank(int blank, struct fb_info *fbi) 1210 + { 1211 + struct omapfb_info *ofbi = FB2OFB(fbi); 1212 + struct omapfb2_device *fbdev = ofbi->fbdev; 1213 + struct omap_dss_device *display = fb2display(fbi); 1214 + int do_update = 0; 1215 + int r = 0; 1216 + 1217 + omapfb_lock(fbdev); 1218 + 1219 + switch (blank) { 1220 + case FB_BLANK_UNBLANK: 1221 + if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) 1222 + goto exit; 1223 + 1224 + if (display->resume) 1225 + r = display->resume(display); 1226 + 1227 + if (r == 0 && display->get_update_mode && 1228 + display->get_update_mode(display) == 1229 + OMAP_DSS_UPDATE_MANUAL) 1230 + do_update = 1; 1231 + 1232 + break; 1233 + 1234 + case FB_BLANK_NORMAL: 1235 + /* FB_BLANK_NORMAL could be implemented. 1236 + * Needs DSS additions. */ 1237 + case FB_BLANK_VSYNC_SUSPEND: 1238 + case FB_BLANK_HSYNC_SUSPEND: 1239 + case FB_BLANK_POWERDOWN: 1240 + if (display->state != OMAP_DSS_DISPLAY_ACTIVE) 1241 + goto exit; 1242 + 1243 + if (display->suspend) 1244 + r = display->suspend(display); 1245 + 1246 + break; 1247 + 1248 + default: 1249 + r = -EINVAL; 1250 + } 1251 + 1252 + exit: 1253 + omapfb_unlock(fbdev); 1254 + 1255 + if (r == 0 && do_update && display->update) { 1256 + u16 w, h; 1257 + display->get_resolution(display, &w, &h); 1258 + 1259 + r = display->update(display, 0, 0, w, h); 1260 + } 1261 + 1262 + return r; 1263 + } 1264 + 1265 + #if 0 1266 + /* XXX fb_read and fb_write are needed for VRFB */ 1267 + ssize_t omapfb_write(struct fb_info *info, const char __user *buf, 1268 + size_t count, loff_t *ppos) 1269 + { 1270 + DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos); 1271 + /* XXX needed for VRFB */ 1272 + return count; 1273 + } 1274 + #endif 1275 + 1276 + static struct fb_ops omapfb_ops = { 1277 + .owner = THIS_MODULE, 1278 + .fb_open = omapfb_open, 1279 + .fb_release = omapfb_release, 1280 + .fb_fillrect = cfb_fillrect, 1281 + .fb_copyarea = cfb_copyarea, 1282 + .fb_imageblit = cfb_imageblit, 1283 + .fb_blank = omapfb_blank, 1284 + .fb_ioctl = omapfb_ioctl, 1285 + .fb_check_var = omapfb_check_var, 1286 + .fb_set_par = omapfb_set_par, 1287 + .fb_pan_display = omapfb_pan_display, 1288 + .fb_mmap = omapfb_mmap, 1289 + .fb_setcolreg = omapfb_setcolreg, 1290 + .fb_setcmap = omapfb_setcmap, 1291 + /*.fb_write = omapfb_write,*/ 1292 + }; 1293 + 1294 + static void omapfb_free_fbmem(struct fb_info *fbi) 1295 + { 1296 + struct omapfb_info *ofbi = FB2OFB(fbi); 1297 + struct omapfb2_device *fbdev = ofbi->fbdev; 1298 + struct omapfb2_mem_region *rg; 1299 + 1300 + rg = &ofbi->region; 1301 + 1302 + if (rg->paddr) 1303 + if (omap_vram_free(rg->paddr, rg->size)) 1304 + dev_err(fbdev->dev, "VRAM FREE failed\n"); 1305 + 1306 + if (rg->vaddr) 1307 + iounmap(rg->vaddr); 1308 + 1309 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 1310 + /* unmap the 0 angle rotation */ 1311 + if (rg->vrfb.vaddr[0]) { 1312 + iounmap(rg->vrfb.vaddr[0]); 1313 + omap_vrfb_release_ctx(&rg->vrfb); 1314 + } 1315 + } 1316 + 1317 + rg->vaddr = NULL; 1318 + rg->paddr = 0; 1319 + rg->alloc = 0; 1320 + rg->size = 0; 1321 + } 1322 + 1323 + static void clear_fb_info(struct fb_info *fbi) 1324 + { 1325 + memset(&fbi->var, 0, sizeof(fbi->var)); 1326 + memset(&fbi->fix, 0, sizeof(fbi->fix)); 1327 + strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id)); 1328 + } 1329 + 1330 + static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev) 1331 + { 1332 + int i; 1333 + 1334 + DBG("free all fbmem\n"); 1335 + 1336 + for (i = 0; i < fbdev->num_fbs; i++) { 1337 + struct fb_info *fbi = fbdev->fbs[i]; 1338 + omapfb_free_fbmem(fbi); 1339 + clear_fb_info(fbi); 1340 + } 1341 + 1342 + return 0; 1343 + } 1344 + 1345 + static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, 1346 + unsigned long paddr) 1347 + { 1348 + struct omapfb_info *ofbi = FB2OFB(fbi); 1349 + struct omapfb2_device *fbdev = ofbi->fbdev; 1350 + struct omapfb2_mem_region *rg; 1351 + void __iomem *vaddr; 1352 + int r; 1353 + 1354 + rg = &ofbi->region; 1355 + memset(rg, 0, sizeof(*rg)); 1356 + 1357 + size = PAGE_ALIGN(size); 1358 + 1359 + if (!paddr) { 1360 + DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); 1361 + r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr); 1362 + } else { 1363 + DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, 1364 + ofbi->id); 1365 + r = omap_vram_reserve(paddr, size); 1366 + } 1367 + 1368 + if (r) { 1369 + dev_err(fbdev->dev, "failed to allocate framebuffer\n"); 1370 + return -ENOMEM; 1371 + } 1372 + 1373 + if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) { 1374 + vaddr = ioremap_wc(paddr, size); 1375 + 1376 + if (!vaddr) { 1377 + dev_err(fbdev->dev, "failed to ioremap framebuffer\n"); 1378 + omap_vram_free(paddr, size); 1379 + return -ENOMEM; 1380 + } 1381 + 1382 + DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr); 1383 + } else { 1384 + r = omap_vrfb_request_ctx(&rg->vrfb); 1385 + if (r) { 1386 + dev_err(fbdev->dev, "vrfb create ctx failed\n"); 1387 + return r; 1388 + } 1389 + 1390 + vaddr = NULL; 1391 + } 1392 + 1393 + rg->paddr = paddr; 1394 + rg->vaddr = vaddr; 1395 + rg->size = size; 1396 + rg->alloc = 1; 1397 + 1398 + return 0; 1399 + } 1400 + 1401 + /* allocate fbmem using display resolution as reference */ 1402 + static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size, 1403 + unsigned long paddr) 1404 + { 1405 + struct omapfb_info *ofbi = FB2OFB(fbi); 1406 + struct omap_dss_device *display; 1407 + int bytespp; 1408 + 1409 + display = fb2display(fbi); 1410 + 1411 + if (!display) 1412 + return 0; 1413 + 1414 + switch (display->get_recommended_bpp(display)) { 1415 + case 16: 1416 + bytespp = 2; 1417 + break; 1418 + case 24: 1419 + bytespp = 4; 1420 + break; 1421 + default: 1422 + bytespp = 4; 1423 + break; 1424 + } 1425 + 1426 + if (!size) { 1427 + u16 w, h; 1428 + 1429 + display->get_resolution(display, &w, &h); 1430 + 1431 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { 1432 + size = max(omap_vrfb_min_phys_size(w, h, bytespp), 1433 + omap_vrfb_min_phys_size(h, w, bytespp)); 1434 + 1435 + DBG("adjusting fb mem size for VRFB, %u -> %lu\n", 1436 + w * h * bytespp, size); 1437 + } else { 1438 + size = w * h * bytespp; 1439 + } 1440 + } 1441 + 1442 + if (!size) 1443 + return 0; 1444 + 1445 + return omapfb_alloc_fbmem(fbi, size, paddr); 1446 + } 1447 + 1448 + static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt) 1449 + { 1450 + enum omap_color_mode mode; 1451 + 1452 + switch (fmt) { 1453 + case OMAPFB_COLOR_RGB565: 1454 + mode = OMAP_DSS_COLOR_RGB16; 1455 + break; 1456 + case OMAPFB_COLOR_YUV422: 1457 + mode = OMAP_DSS_COLOR_YUV2; 1458 + break; 1459 + case OMAPFB_COLOR_CLUT_8BPP: 1460 + mode = OMAP_DSS_COLOR_CLUT8; 1461 + break; 1462 + case OMAPFB_COLOR_CLUT_4BPP: 1463 + mode = OMAP_DSS_COLOR_CLUT4; 1464 + break; 1465 + case OMAPFB_COLOR_CLUT_2BPP: 1466 + mode = OMAP_DSS_COLOR_CLUT2; 1467 + break; 1468 + case OMAPFB_COLOR_CLUT_1BPP: 1469 + mode = OMAP_DSS_COLOR_CLUT1; 1470 + break; 1471 + case OMAPFB_COLOR_RGB444: 1472 + mode = OMAP_DSS_COLOR_RGB12U; 1473 + break; 1474 + case OMAPFB_COLOR_YUY422: 1475 + mode = OMAP_DSS_COLOR_UYVY; 1476 + break; 1477 + case OMAPFB_COLOR_ARGB16: 1478 + mode = OMAP_DSS_COLOR_ARGB16; 1479 + break; 1480 + case OMAPFB_COLOR_RGB24U: 1481 + mode = OMAP_DSS_COLOR_RGB24U; 1482 + break; 1483 + case OMAPFB_COLOR_RGB24P: 1484 + mode = OMAP_DSS_COLOR_RGB24P; 1485 + break; 1486 + case OMAPFB_COLOR_ARGB32: 1487 + mode = OMAP_DSS_COLOR_ARGB32; 1488 + break; 1489 + case OMAPFB_COLOR_RGBA32: 1490 + mode = OMAP_DSS_COLOR_RGBA32; 1491 + break; 1492 + case OMAPFB_COLOR_RGBX32: 1493 + mode = OMAP_DSS_COLOR_RGBX32; 1494 + break; 1495 + default: 1496 + mode = -EINVAL; 1497 + } 1498 + 1499 + return mode; 1500 + } 1501 + 1502 + static int omapfb_parse_vram_param(const char *param, int max_entries, 1503 + unsigned long *sizes, unsigned long *paddrs) 1504 + { 1505 + int fbnum; 1506 + unsigned long size; 1507 + unsigned long paddr = 0; 1508 + char *p, *start; 1509 + 1510 + start = (char *)param; 1511 + 1512 + while (1) { 1513 + p = start; 1514 + 1515 + fbnum = simple_strtoul(p, &p, 10); 1516 + 1517 + if (p == param) 1518 + return -EINVAL; 1519 + 1520 + if (*p != ':') 1521 + return -EINVAL; 1522 + 1523 + if (fbnum >= max_entries) 1524 + return -EINVAL; 1525 + 1526 + size = memparse(p + 1, &p); 1527 + 1528 + if (!size) 1529 + return -EINVAL; 1530 + 1531 + paddr = 0; 1532 + 1533 + if (*p == '@') { 1534 + paddr = simple_strtoul(p + 1, &p, 16); 1535 + 1536 + if (!paddr) 1537 + return -EINVAL; 1538 + 1539 + } 1540 + 1541 + paddrs[fbnum] = paddr; 1542 + sizes[fbnum] = size; 1543 + 1544 + if (*p == 0) 1545 + break; 1546 + 1547 + if (*p != ',') 1548 + return -EINVAL; 1549 + 1550 + ++p; 1551 + 1552 + start = p; 1553 + } 1554 + 1555 + return 0; 1556 + } 1557 + 1558 + static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) 1559 + { 1560 + int i, r; 1561 + unsigned long vram_sizes[10]; 1562 + unsigned long vram_paddrs[10]; 1563 + 1564 + memset(&vram_sizes, 0, sizeof(vram_sizes)); 1565 + memset(&vram_paddrs, 0, sizeof(vram_paddrs)); 1566 + 1567 + if (def_vram && omapfb_parse_vram_param(def_vram, 10, 1568 + vram_sizes, vram_paddrs)) { 1569 + dev_err(fbdev->dev, "failed to parse vram parameter\n"); 1570 + 1571 + memset(&vram_sizes, 0, sizeof(vram_sizes)); 1572 + memset(&vram_paddrs, 0, sizeof(vram_paddrs)); 1573 + } 1574 + 1575 + if (fbdev->dev->platform_data) { 1576 + struct omapfb_platform_data *opd; 1577 + opd = fbdev->dev->platform_data; 1578 + for (i = 0; i < opd->mem_desc.region_cnt; ++i) { 1579 + if (!vram_sizes[i]) { 1580 + unsigned long size; 1581 + unsigned long paddr; 1582 + 1583 + size = opd->mem_desc.region[i].size; 1584 + paddr = opd->mem_desc.region[i].paddr; 1585 + 1586 + vram_sizes[i] = size; 1587 + vram_paddrs[i] = paddr; 1588 + } 1589 + } 1590 + } 1591 + 1592 + for (i = 0; i < fbdev->num_fbs; i++) { 1593 + /* allocate memory automatically only for fb0, or if 1594 + * excplicitly defined with vram or plat data option */ 1595 + if (i == 0 || vram_sizes[i] != 0) { 1596 + r = omapfb_alloc_fbmem_display(fbdev->fbs[i], 1597 + vram_sizes[i], vram_paddrs[i]); 1598 + 1599 + if (r) 1600 + return r; 1601 + } 1602 + } 1603 + 1604 + for (i = 0; i < fbdev->num_fbs; i++) { 1605 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 1606 + struct omapfb2_mem_region *rg; 1607 + rg = &ofbi->region; 1608 + 1609 + DBG("region%d phys %08x virt %p size=%lu\n", 1610 + i, 1611 + rg->paddr, 1612 + rg->vaddr, 1613 + rg->size); 1614 + } 1615 + 1616 + return 0; 1617 + } 1618 + 1619 + int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) 1620 + { 1621 + struct omapfb_info *ofbi = FB2OFB(fbi); 1622 + struct omapfb2_device *fbdev = ofbi->fbdev; 1623 + struct omap_dss_device *display = fb2display(fbi); 1624 + struct omapfb2_mem_region *rg = &ofbi->region; 1625 + unsigned long old_size = rg->size; 1626 + unsigned long old_paddr = rg->paddr; 1627 + int old_type = rg->type; 1628 + int r; 1629 + 1630 + if (type > OMAPFB_MEMTYPE_MAX) 1631 + return -EINVAL; 1632 + 1633 + size = PAGE_ALIGN(size); 1634 + 1635 + if (old_size == size && old_type == type) 1636 + return 0; 1637 + 1638 + if (display && display->sync) 1639 + display->sync(display); 1640 + 1641 + omapfb_free_fbmem(fbi); 1642 + 1643 + if (size == 0) { 1644 + clear_fb_info(fbi); 1645 + return 0; 1646 + } 1647 + 1648 + r = omapfb_alloc_fbmem(fbi, size, 0); 1649 + 1650 + if (r) { 1651 + if (old_size) 1652 + omapfb_alloc_fbmem(fbi, old_size, old_paddr); 1653 + 1654 + if (rg->size == 0) 1655 + clear_fb_info(fbi); 1656 + 1657 + return r; 1658 + } 1659 + 1660 + if (old_size == size) 1661 + return 0; 1662 + 1663 + if (old_size == 0) { 1664 + DBG("initializing fb %d\n", ofbi->id); 1665 + r = omapfb_fb_init(fbdev, fbi); 1666 + if (r) { 1667 + DBG("omapfb_fb_init failed\n"); 1668 + goto err; 1669 + } 1670 + r = omapfb_apply_changes(fbi, 1); 1671 + if (r) { 1672 + DBG("omapfb_apply_changes failed\n"); 1673 + goto err; 1674 + } 1675 + } else { 1676 + struct fb_var_screeninfo new_var; 1677 + memcpy(&new_var, &fbi->var, sizeof(new_var)); 1678 + r = check_fb_var(fbi, &new_var); 1679 + if (r) 1680 + goto err; 1681 + memcpy(&fbi->var, &new_var, sizeof(fbi->var)); 1682 + set_fb_fix(fbi); 1683 + r = setup_vrfb_rotation(fbi); 1684 + if (r) 1685 + goto err; 1686 + } 1687 + 1688 + return 0; 1689 + err: 1690 + omapfb_free_fbmem(fbi); 1691 + clear_fb_info(fbi); 1692 + return r; 1693 + } 1694 + 1695 + /* initialize fb_info, var, fix to something sane based on the display */ 1696 + static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) 1697 + { 1698 + struct fb_var_screeninfo *var = &fbi->var; 1699 + struct omap_dss_device *display = fb2display(fbi); 1700 + struct omapfb_info *ofbi = FB2OFB(fbi); 1701 + int r = 0; 1702 + 1703 + fbi->fbops = &omapfb_ops; 1704 + fbi->flags = FBINFO_FLAG_DEFAULT; 1705 + fbi->pseudo_palette = fbdev->pseudo_palette; 1706 + 1707 + if (ofbi->region.size == 0) { 1708 + clear_fb_info(fbi); 1709 + return 0; 1710 + } 1711 + 1712 + var->nonstd = 0; 1713 + var->bits_per_pixel = 0; 1714 + 1715 + var->rotate = def_rotate; 1716 + 1717 + /* 1718 + * Check if there is a default color format set in the board file, 1719 + * and use this format instead the default deducted from the 1720 + * display bpp. 1721 + */ 1722 + if (fbdev->dev->platform_data) { 1723 + struct omapfb_platform_data *opd; 1724 + int id = ofbi->id; 1725 + 1726 + opd = fbdev->dev->platform_data; 1727 + if (opd->mem_desc.region[id].format_used) { 1728 + enum omap_color_mode mode; 1729 + enum omapfb_color_format format; 1730 + 1731 + format = opd->mem_desc.region[id].format; 1732 + mode = fb_format_to_dss_mode(format); 1733 + if (mode < 0) { 1734 + r = mode; 1735 + goto err; 1736 + } 1737 + r = dss_mode_to_fb_mode(mode, var); 1738 + if (r < 0) 1739 + goto err; 1740 + } 1741 + } 1742 + 1743 + if (display) { 1744 + u16 w, h; 1745 + int rotation = (var->rotate + ofbi->rotation[0]) % 4; 1746 + 1747 + display->get_resolution(display, &w, &h); 1748 + 1749 + if (rotation == FB_ROTATE_CW || 1750 + rotation == FB_ROTATE_CCW) { 1751 + var->xres = h; 1752 + var->yres = w; 1753 + } else { 1754 + var->xres = w; 1755 + var->yres = h; 1756 + } 1757 + 1758 + var->xres_virtual = var->xres; 1759 + var->yres_virtual = var->yres; 1760 + 1761 + if (!var->bits_per_pixel) { 1762 + switch (display->get_recommended_bpp(display)) { 1763 + case 16: 1764 + var->bits_per_pixel = 16; 1765 + break; 1766 + case 24: 1767 + var->bits_per_pixel = 32; 1768 + break; 1769 + default: 1770 + dev_err(fbdev->dev, "illegal display " 1771 + "bpp\n"); 1772 + return -EINVAL; 1773 + } 1774 + } 1775 + } else { 1776 + /* if there's no display, let's just guess some basic values */ 1777 + var->xres = 320; 1778 + var->yres = 240; 1779 + var->xres_virtual = var->xres; 1780 + var->yres_virtual = var->yres; 1781 + if (!var->bits_per_pixel) 1782 + var->bits_per_pixel = 16; 1783 + } 1784 + 1785 + r = check_fb_var(fbi, var); 1786 + if (r) 1787 + goto err; 1788 + 1789 + set_fb_fix(fbi); 1790 + r = setup_vrfb_rotation(fbi); 1791 + if (r) 1792 + goto err; 1793 + 1794 + r = fb_alloc_cmap(&fbi->cmap, 256, 0); 1795 + if (r) 1796 + dev_err(fbdev->dev, "unable to allocate color map memory\n"); 1797 + 1798 + err: 1799 + return r; 1800 + } 1801 + 1802 + static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi) 1803 + { 1804 + fb_dealloc_cmap(&fbi->cmap); 1805 + } 1806 + 1807 + 1808 + static void omapfb_free_resources(struct omapfb2_device *fbdev) 1809 + { 1810 + int i; 1811 + 1812 + DBG("free_resources\n"); 1813 + 1814 + if (fbdev == NULL) 1815 + return; 1816 + 1817 + for (i = 0; i < fbdev->num_fbs; i++) 1818 + unregister_framebuffer(fbdev->fbs[i]); 1819 + 1820 + /* free the reserved fbmem */ 1821 + omapfb_free_all_fbmem(fbdev); 1822 + 1823 + for (i = 0; i < fbdev->num_fbs; i++) { 1824 + fbinfo_cleanup(fbdev, fbdev->fbs[i]); 1825 + framebuffer_release(fbdev->fbs[i]); 1826 + } 1827 + 1828 + for (i = 0; i < fbdev->num_displays; i++) { 1829 + if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED) 1830 + fbdev->displays[i]->disable(fbdev->displays[i]); 1831 + 1832 + omap_dss_put_device(fbdev->displays[i]); 1833 + } 1834 + 1835 + dev_set_drvdata(fbdev->dev, NULL); 1836 + kfree(fbdev); 1837 + } 1838 + 1839 + static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) 1840 + { 1841 + int r, i; 1842 + 1843 + fbdev->num_fbs = 0; 1844 + 1845 + DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS); 1846 + 1847 + /* allocate fb_infos */ 1848 + for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) { 1849 + struct fb_info *fbi; 1850 + struct omapfb_info *ofbi; 1851 + 1852 + fbi = framebuffer_alloc(sizeof(struct omapfb_info), 1853 + fbdev->dev); 1854 + 1855 + if (fbi == NULL) { 1856 + dev_err(fbdev->dev, 1857 + "unable to allocate memory for plane info\n"); 1858 + return -ENOMEM; 1859 + } 1860 + 1861 + clear_fb_info(fbi); 1862 + 1863 + fbdev->fbs[i] = fbi; 1864 + 1865 + ofbi = FB2OFB(fbi); 1866 + ofbi->fbdev = fbdev; 1867 + ofbi->id = i; 1868 + 1869 + /* assign these early, so that fb alloc can use them */ 1870 + ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : 1871 + OMAP_DSS_ROT_DMA; 1872 + ofbi->mirror = def_mirror; 1873 + 1874 + fbdev->num_fbs++; 1875 + } 1876 + 1877 + DBG("fb_infos allocated\n"); 1878 + 1879 + /* assign overlays for the fbs */ 1880 + for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) { 1881 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 1882 + 1883 + ofbi->overlays[0] = fbdev->overlays[i]; 1884 + ofbi->num_overlays = 1; 1885 + } 1886 + 1887 + /* allocate fb memories */ 1888 + r = omapfb_allocate_all_fbs(fbdev); 1889 + if (r) { 1890 + dev_err(fbdev->dev, "failed to allocate fbmem\n"); 1891 + return r; 1892 + } 1893 + 1894 + DBG("fbmems allocated\n"); 1895 + 1896 + /* setup fb_infos */ 1897 + for (i = 0; i < fbdev->num_fbs; i++) { 1898 + r = omapfb_fb_init(fbdev, fbdev->fbs[i]); 1899 + if (r) { 1900 + dev_err(fbdev->dev, "failed to setup fb_info\n"); 1901 + return r; 1902 + } 1903 + } 1904 + 1905 + DBG("fb_infos initialized\n"); 1906 + 1907 + for (i = 0; i < fbdev->num_fbs; i++) { 1908 + r = register_framebuffer(fbdev->fbs[i]); 1909 + if (r != 0) { 1910 + dev_err(fbdev->dev, 1911 + "registering framebuffer %d failed\n", i); 1912 + return r; 1913 + } 1914 + } 1915 + 1916 + DBG("framebuffers registered\n"); 1917 + 1918 + for (i = 0; i < fbdev->num_fbs; i++) { 1919 + r = omapfb_apply_changes(fbdev->fbs[i], 1); 1920 + if (r) { 1921 + dev_err(fbdev->dev, "failed to change mode\n"); 1922 + return r; 1923 + } 1924 + } 1925 + 1926 + DBG("create sysfs for fbs\n"); 1927 + r = omapfb_create_sysfs(fbdev); 1928 + if (r) { 1929 + dev_err(fbdev->dev, "failed to create sysfs entries\n"); 1930 + return r; 1931 + } 1932 + 1933 + /* Enable fb0 */ 1934 + if (fbdev->num_fbs > 0) { 1935 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); 1936 + 1937 + if (ofbi->num_overlays > 0) { 1938 + struct omap_overlay *ovl = ofbi->overlays[0]; 1939 + 1940 + r = omapfb_overlay_enable(ovl, 1); 1941 + 1942 + if (r) { 1943 + dev_err(fbdev->dev, 1944 + "failed to enable overlay\n"); 1945 + return r; 1946 + } 1947 + } 1948 + } 1949 + 1950 + DBG("create_framebuffers done\n"); 1951 + 1952 + return 0; 1953 + } 1954 + 1955 + static int omapfb_mode_to_timings(const char *mode_str, 1956 + struct omap_video_timings *timings, u8 *bpp) 1957 + { 1958 + struct fb_info fbi; 1959 + struct fb_var_screeninfo var; 1960 + struct fb_ops fbops; 1961 + int r; 1962 + 1963 + #ifdef CONFIG_OMAP2_DSS_VENC 1964 + if (strcmp(mode_str, "pal") == 0) { 1965 + *timings = omap_dss_pal_timings; 1966 + *bpp = 0; 1967 + return 0; 1968 + } else if (strcmp(mode_str, "ntsc") == 0) { 1969 + *timings = omap_dss_ntsc_timings; 1970 + *bpp = 0; 1971 + return 0; 1972 + } 1973 + #endif 1974 + 1975 + /* this is quite a hack, but I wanted to use the modedb and for 1976 + * that we need fb_info and var, so we create dummy ones */ 1977 + 1978 + memset(&fbi, 0, sizeof(fbi)); 1979 + memset(&var, 0, sizeof(var)); 1980 + memset(&fbops, 0, sizeof(fbops)); 1981 + fbi.fbops = &fbops; 1982 + 1983 + r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24); 1984 + 1985 + if (r != 0) { 1986 + timings->pixel_clock = PICOS2KHZ(var.pixclock); 1987 + timings->hfp = var.left_margin; 1988 + timings->hbp = var.right_margin; 1989 + timings->vfp = var.upper_margin; 1990 + timings->vbp = var.lower_margin; 1991 + timings->hsw = var.hsync_len; 1992 + timings->vsw = var.vsync_len; 1993 + timings->x_res = var.xres; 1994 + timings->y_res = var.yres; 1995 + 1996 + switch (var.bits_per_pixel) { 1997 + case 16: 1998 + *bpp = 16; 1999 + break; 2000 + case 24: 2001 + case 32: 2002 + default: 2003 + *bpp = 24; 2004 + break; 2005 + } 2006 + 2007 + return 0; 2008 + } else { 2009 + return -EINVAL; 2010 + } 2011 + } 2012 + 2013 + static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str) 2014 + { 2015 + int r; 2016 + u8 bpp; 2017 + struct omap_video_timings timings; 2018 + 2019 + r = omapfb_mode_to_timings(mode_str, &timings, &bpp); 2020 + if (r) 2021 + return r; 2022 + 2023 + display->panel.recommended_bpp = bpp; 2024 + 2025 + if (!display->check_timings || !display->set_timings) 2026 + return -EINVAL; 2027 + 2028 + r = display->check_timings(display, &timings); 2029 + if (r) 2030 + return r; 2031 + 2032 + display->set_timings(display, &timings); 2033 + 2034 + return 0; 2035 + } 2036 + 2037 + static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) 2038 + { 2039 + char *str, *options, *this_opt; 2040 + int r = 0; 2041 + 2042 + str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL); 2043 + strcpy(str, def_mode); 2044 + options = str; 2045 + 2046 + while (!r && (this_opt = strsep(&options, ",")) != NULL) { 2047 + char *p, *display_str, *mode_str; 2048 + struct omap_dss_device *display; 2049 + int i; 2050 + 2051 + p = strchr(this_opt, ':'); 2052 + if (!p) { 2053 + r = -EINVAL; 2054 + break; 2055 + } 2056 + 2057 + *p = 0; 2058 + display_str = this_opt; 2059 + mode_str = p + 1; 2060 + 2061 + display = NULL; 2062 + for (i = 0; i < fbdev->num_displays; ++i) { 2063 + if (strcmp(fbdev->displays[i]->name, 2064 + display_str) == 0) { 2065 + display = fbdev->displays[i]; 2066 + break; 2067 + } 2068 + } 2069 + 2070 + if (!display) { 2071 + r = -EINVAL; 2072 + break; 2073 + } 2074 + 2075 + r = omapfb_set_def_mode(display, mode_str); 2076 + if (r) 2077 + break; 2078 + } 2079 + 2080 + kfree(str); 2081 + 2082 + return r; 2083 + } 2084 + 2085 + static int omapfb_probe(struct platform_device *pdev) 2086 + { 2087 + struct omapfb2_device *fbdev = NULL; 2088 + int r = 0; 2089 + int i; 2090 + struct omap_overlay *ovl; 2091 + struct omap_dss_device *def_display; 2092 + struct omap_dss_device *dssdev; 2093 + 2094 + DBG("omapfb_probe\n"); 2095 + 2096 + if (pdev->num_resources != 0) { 2097 + dev_err(&pdev->dev, "probed for an unknown device\n"); 2098 + r = -ENODEV; 2099 + goto err0; 2100 + } 2101 + 2102 + fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL); 2103 + if (fbdev == NULL) { 2104 + r = -ENOMEM; 2105 + goto err0; 2106 + } 2107 + 2108 + mutex_init(&fbdev->mtx); 2109 + 2110 + fbdev->dev = &pdev->dev; 2111 + platform_set_drvdata(pdev, fbdev); 2112 + 2113 + fbdev->num_displays = 0; 2114 + dssdev = NULL; 2115 + for_each_dss_dev(dssdev) { 2116 + omap_dss_get_device(dssdev); 2117 + fbdev->displays[fbdev->num_displays++] = dssdev; 2118 + } 2119 + 2120 + if (fbdev->num_displays == 0) { 2121 + dev_err(&pdev->dev, "no displays\n"); 2122 + r = -EINVAL; 2123 + goto cleanup; 2124 + } 2125 + 2126 + fbdev->num_overlays = omap_dss_get_num_overlays(); 2127 + for (i = 0; i < fbdev->num_overlays; i++) 2128 + fbdev->overlays[i] = omap_dss_get_overlay(i); 2129 + 2130 + fbdev->num_managers = omap_dss_get_num_overlay_managers(); 2131 + for (i = 0; i < fbdev->num_managers; i++) 2132 + fbdev->managers[i] = omap_dss_get_overlay_manager(i); 2133 + 2134 + if (def_mode && strlen(def_mode) > 0) { 2135 + if (omapfb_parse_def_modes(fbdev)) 2136 + dev_warn(&pdev->dev, "cannot parse default modes\n"); 2137 + } 2138 + 2139 + r = omapfb_create_framebuffers(fbdev); 2140 + if (r) 2141 + goto cleanup; 2142 + 2143 + for (i = 0; i < fbdev->num_managers; i++) { 2144 + struct omap_overlay_manager *mgr; 2145 + mgr = fbdev->managers[i]; 2146 + r = mgr->apply(mgr); 2147 + if (r) 2148 + dev_warn(fbdev->dev, "failed to apply dispc config\n"); 2149 + } 2150 + 2151 + DBG("mgr->apply'ed\n"); 2152 + 2153 + /* gfx overlay should be the default one. find a display 2154 + * connected to that, and use it as default display */ 2155 + ovl = omap_dss_get_overlay(0); 2156 + if (ovl->manager && ovl->manager->device) { 2157 + def_display = ovl->manager->device; 2158 + } else { 2159 + dev_warn(&pdev->dev, "cannot find default display\n"); 2160 + def_display = NULL; 2161 + } 2162 + 2163 + if (def_display) { 2164 + #ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE 2165 + u16 w, h; 2166 + #endif 2167 + r = def_display->enable(def_display); 2168 + if (r) 2169 + dev_warn(fbdev->dev, "Failed to enable display '%s'\n", 2170 + def_display->name); 2171 + 2172 + /* set the update mode */ 2173 + if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { 2174 + #ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE 2175 + if (def_display->enable_te) 2176 + def_display->enable_te(def_display, 1); 2177 + if (def_display->set_update_mode) 2178 + def_display->set_update_mode(def_display, 2179 + OMAP_DSS_UPDATE_AUTO); 2180 + #else /* MANUAL_UPDATE */ 2181 + if (def_display->enable_te) 2182 + def_display->enable_te(def_display, 0); 2183 + if (def_display->set_update_mode) 2184 + def_display->set_update_mode(def_display, 2185 + OMAP_DSS_UPDATE_MANUAL); 2186 + 2187 + def_display->get_resolution(def_display, &w, &h); 2188 + def_display->update(def_display, 0, 0, w, h); 2189 + #endif 2190 + } else { 2191 + if (def_display->set_update_mode) 2192 + def_display->set_update_mode(def_display, 2193 + OMAP_DSS_UPDATE_AUTO); 2194 + } 2195 + } 2196 + 2197 + return 0; 2198 + 2199 + cleanup: 2200 + omapfb_free_resources(fbdev); 2201 + err0: 2202 + dev_err(&pdev->dev, "failed to setup omapfb\n"); 2203 + return r; 2204 + } 2205 + 2206 + static int omapfb_remove(struct platform_device *pdev) 2207 + { 2208 + struct omapfb2_device *fbdev = platform_get_drvdata(pdev); 2209 + 2210 + /* FIXME: wait till completion of pending events */ 2211 + 2212 + omapfb_remove_sysfs(fbdev); 2213 + 2214 + omapfb_free_resources(fbdev); 2215 + 2216 + return 0; 2217 + } 2218 + 2219 + static struct platform_driver omapfb_driver = { 2220 + .probe = omapfb_probe, 2221 + .remove = omapfb_remove, 2222 + .driver = { 2223 + .name = "omapfb", 2224 + .owner = THIS_MODULE, 2225 + }, 2226 + }; 2227 + 2228 + static int __init omapfb_init(void) 2229 + { 2230 + DBG("omapfb_init\n"); 2231 + 2232 + if (platform_driver_register(&omapfb_driver)) { 2233 + printk(KERN_ERR "failed to register omapfb driver\n"); 2234 + return -ENODEV; 2235 + } 2236 + 2237 + return 0; 2238 + } 2239 + 2240 + static void __exit omapfb_exit(void) 2241 + { 2242 + DBG("omapfb_exit\n"); 2243 + platform_driver_unregister(&omapfb_driver); 2244 + } 2245 + 2246 + module_param_named(mode, def_mode, charp, 0); 2247 + module_param_named(vram, def_vram, charp, 0); 2248 + module_param_named(rotate, def_rotate, int, 0); 2249 + module_param_named(vrfb, def_vrfb, bool, 0); 2250 + module_param_named(mirror, def_mirror, bool, 0); 2251 + 2252 + /* late_initcall to let panel/ctrl drivers loaded first. 2253 + * I guess better option would be a more dynamic approach, 2254 + * so that omapfb reacts to new panels when they are loaded */ 2255 + late_initcall(omapfb_init); 2256 + /*module_init(omapfb_init);*/ 2257 + module_exit(omapfb_exit); 2258 + 2259 + MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); 2260 + MODULE_DESCRIPTION("OMAP2/3 Framebuffer"); 2261 + MODULE_LICENSE("GPL v2");
+507
drivers/video/omap2/omapfb/omapfb-sysfs.c
··· 1 + /* 2 + * linux/drivers/video/omap2/omapfb-sysfs.c 3 + * 4 + * Copyright (C) 2008 Nokia Corporation 5 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 6 + * 7 + * Some code and ideas taken from drivers/video/omap/ driver 8 + * by Imre Deak. 9 + * 10 + * This program is free software; you can redistribute it and/or modify it 11 + * under the terms of the GNU General Public License version 2 as published by 12 + * the Free Software Foundation. 13 + * 14 + * This program is distributed in the hope that it will be useful, but WITHOUT 15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 + * more details. 18 + * 19 + * You should have received a copy of the GNU General Public License along with 20 + * this program. If not, see <http://www.gnu.org/licenses/>. 21 + */ 22 + 23 + #include <linux/fb.h> 24 + #include <linux/sysfs.h> 25 + #include <linux/device.h> 26 + #include <linux/uaccess.h> 27 + #include <linux/platform_device.h> 28 + #include <linux/kernel.h> 29 + #include <linux/mm.h> 30 + #include <linux/omapfb.h> 31 + 32 + #include <plat/display.h> 33 + #include <plat/vrfb.h> 34 + 35 + #include "omapfb.h" 36 + 37 + static ssize_t show_rotate_type(struct device *dev, 38 + struct device_attribute *attr, char *buf) 39 + { 40 + struct fb_info *fbi = dev_get_drvdata(dev); 41 + struct omapfb_info *ofbi = FB2OFB(fbi); 42 + 43 + return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type); 44 + } 45 + 46 + static ssize_t store_rotate_type(struct device *dev, 47 + struct device_attribute *attr, 48 + const char *buf, size_t count) 49 + { 50 + struct fb_info *fbi = dev_get_drvdata(dev); 51 + struct omapfb_info *ofbi = FB2OFB(fbi); 52 + enum omap_dss_rotation_type rot_type; 53 + int r; 54 + 55 + rot_type = simple_strtoul(buf, NULL, 0); 56 + 57 + if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB) 58 + return -EINVAL; 59 + 60 + lock_fb_info(fbi); 61 + 62 + r = 0; 63 + if (rot_type == ofbi->rotation_type) 64 + goto out; 65 + 66 + if (ofbi->region.size) { 67 + r = -EBUSY; 68 + goto out; 69 + } 70 + 71 + ofbi->rotation_type = rot_type; 72 + 73 + /* 74 + * Since the VRAM for this FB is not allocated at the moment we don't 75 + * need to do any further parameter checking at this point. 76 + */ 77 + out: 78 + unlock_fb_info(fbi); 79 + 80 + return r ? r : count; 81 + } 82 + 83 + 84 + static ssize_t show_mirror(struct device *dev, 85 + struct device_attribute *attr, char *buf) 86 + { 87 + struct fb_info *fbi = dev_get_drvdata(dev); 88 + struct omapfb_info *ofbi = FB2OFB(fbi); 89 + 90 + return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror); 91 + } 92 + 93 + static ssize_t store_mirror(struct device *dev, 94 + struct device_attribute *attr, 95 + const char *buf, size_t count) 96 + { 97 + struct fb_info *fbi = dev_get_drvdata(dev); 98 + struct omapfb_info *ofbi = FB2OFB(fbi); 99 + bool mirror; 100 + int r; 101 + struct fb_var_screeninfo new_var; 102 + 103 + mirror = simple_strtoul(buf, NULL, 0); 104 + 105 + if (mirror != 0 && mirror != 1) 106 + return -EINVAL; 107 + 108 + lock_fb_info(fbi); 109 + 110 + ofbi->mirror = mirror; 111 + 112 + memcpy(&new_var, &fbi->var, sizeof(new_var)); 113 + r = check_fb_var(fbi, &new_var); 114 + if (r) 115 + goto out; 116 + memcpy(&fbi->var, &new_var, sizeof(fbi->var)); 117 + 118 + set_fb_fix(fbi); 119 + 120 + r = omapfb_apply_changes(fbi, 0); 121 + if (r) 122 + goto out; 123 + 124 + r = count; 125 + out: 126 + unlock_fb_info(fbi); 127 + 128 + return r; 129 + } 130 + 131 + static ssize_t show_overlays(struct device *dev, 132 + struct device_attribute *attr, char *buf) 133 + { 134 + struct fb_info *fbi = dev_get_drvdata(dev); 135 + struct omapfb_info *ofbi = FB2OFB(fbi); 136 + struct omapfb2_device *fbdev = ofbi->fbdev; 137 + ssize_t l = 0; 138 + int t; 139 + 140 + omapfb_lock(fbdev); 141 + lock_fb_info(fbi); 142 + 143 + for (t = 0; t < ofbi->num_overlays; t++) { 144 + struct omap_overlay *ovl = ofbi->overlays[t]; 145 + int ovlnum; 146 + 147 + for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum) 148 + if (ovl == fbdev->overlays[ovlnum]) 149 + break; 150 + 151 + l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", 152 + t == 0 ? "" : ",", ovlnum); 153 + } 154 + 155 + l += snprintf(buf + l, PAGE_SIZE - l, "\n"); 156 + 157 + unlock_fb_info(fbi); 158 + omapfb_unlock(fbdev); 159 + 160 + return l; 161 + } 162 + 163 + static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev, 164 + struct omap_overlay *ovl) 165 + { 166 + int i, t; 167 + 168 + for (i = 0; i < fbdev->num_fbs; i++) { 169 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 170 + 171 + for (t = 0; t < ofbi->num_overlays; t++) { 172 + if (ofbi->overlays[t] == ovl) 173 + return ofbi; 174 + } 175 + } 176 + 177 + return NULL; 178 + } 179 + 180 + static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, 181 + const char *buf, size_t count) 182 + { 183 + struct fb_info *fbi = dev_get_drvdata(dev); 184 + struct omapfb_info *ofbi = FB2OFB(fbi); 185 + struct omapfb2_device *fbdev = ofbi->fbdev; 186 + struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB]; 187 + struct omap_overlay *ovl; 188 + int num_ovls, r, i; 189 + int len; 190 + bool added = false; 191 + 192 + num_ovls = 0; 193 + 194 + len = strlen(buf); 195 + if (buf[len - 1] == '\n') 196 + len = len - 1; 197 + 198 + omapfb_lock(fbdev); 199 + lock_fb_info(fbi); 200 + 201 + if (len > 0) { 202 + char *p = (char *)buf; 203 + int ovlnum; 204 + 205 + while (p < buf + len) { 206 + int found; 207 + if (num_ovls == OMAPFB_MAX_OVL_PER_FB) { 208 + r = -EINVAL; 209 + goto out; 210 + } 211 + 212 + ovlnum = simple_strtoul(p, &p, 0); 213 + if (ovlnum > fbdev->num_overlays) { 214 + r = -EINVAL; 215 + goto out; 216 + } 217 + 218 + found = 0; 219 + for (i = 0; i < num_ovls; ++i) { 220 + if (ovls[i] == fbdev->overlays[ovlnum]) { 221 + found = 1; 222 + break; 223 + } 224 + } 225 + 226 + if (!found) 227 + ovls[num_ovls++] = fbdev->overlays[ovlnum]; 228 + 229 + p++; 230 + } 231 + } 232 + 233 + for (i = 0; i < num_ovls; ++i) { 234 + struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]); 235 + if (ofbi2 && ofbi2 != ofbi) { 236 + dev_err(fbdev->dev, "overlay already in use\n"); 237 + r = -EINVAL; 238 + goto out; 239 + } 240 + } 241 + 242 + /* detach unused overlays */ 243 + for (i = 0; i < ofbi->num_overlays; ++i) { 244 + int t, found; 245 + 246 + ovl = ofbi->overlays[i]; 247 + 248 + found = 0; 249 + 250 + for (t = 0; t < num_ovls; ++t) { 251 + if (ovl == ovls[t]) { 252 + found = 1; 253 + break; 254 + } 255 + } 256 + 257 + if (found) 258 + continue; 259 + 260 + DBG("detaching %d\n", ofbi->overlays[i]->id); 261 + 262 + omapfb_overlay_enable(ovl, 0); 263 + 264 + if (ovl->manager) 265 + ovl->manager->apply(ovl->manager); 266 + 267 + for (t = i + 1; t < ofbi->num_overlays; t++) { 268 + ofbi->rotation[t-1] = ofbi->rotation[t]; 269 + ofbi->overlays[t-1] = ofbi->overlays[t]; 270 + } 271 + 272 + ofbi->num_overlays--; 273 + i--; 274 + } 275 + 276 + for (i = 0; i < num_ovls; ++i) { 277 + int t, found; 278 + 279 + ovl = ovls[i]; 280 + 281 + found = 0; 282 + 283 + for (t = 0; t < ofbi->num_overlays; ++t) { 284 + if (ovl == ofbi->overlays[t]) { 285 + found = 1; 286 + break; 287 + } 288 + } 289 + 290 + if (found) 291 + continue; 292 + ofbi->rotation[ofbi->num_overlays] = 0; 293 + ofbi->overlays[ofbi->num_overlays++] = ovl; 294 + 295 + added = true; 296 + } 297 + 298 + if (added) { 299 + r = omapfb_apply_changes(fbi, 0); 300 + if (r) 301 + goto out; 302 + } 303 + 304 + r = count; 305 + out: 306 + unlock_fb_info(fbi); 307 + omapfb_unlock(fbdev); 308 + 309 + return r; 310 + } 311 + 312 + static ssize_t show_overlays_rotate(struct device *dev, 313 + struct device_attribute *attr, char *buf) 314 + { 315 + struct fb_info *fbi = dev_get_drvdata(dev); 316 + struct omapfb_info *ofbi = FB2OFB(fbi); 317 + ssize_t l = 0; 318 + int t; 319 + 320 + lock_fb_info(fbi); 321 + 322 + for (t = 0; t < ofbi->num_overlays; t++) { 323 + l += snprintf(buf + l, PAGE_SIZE - l, "%s%d", 324 + t == 0 ? "" : ",", ofbi->rotation[t]); 325 + } 326 + 327 + l += snprintf(buf + l, PAGE_SIZE - l, "\n"); 328 + 329 + unlock_fb_info(fbi); 330 + 331 + return l; 332 + } 333 + 334 + static ssize_t store_overlays_rotate(struct device *dev, 335 + struct device_attribute *attr, const char *buf, size_t count) 336 + { 337 + struct fb_info *fbi = dev_get_drvdata(dev); 338 + struct omapfb_info *ofbi = FB2OFB(fbi); 339 + int num_ovls = 0, r, i; 340 + int len; 341 + bool changed = false; 342 + u8 rotation[OMAPFB_MAX_OVL_PER_FB]; 343 + 344 + len = strlen(buf); 345 + if (buf[len - 1] == '\n') 346 + len = len - 1; 347 + 348 + lock_fb_info(fbi); 349 + 350 + if (len > 0) { 351 + char *p = (char *)buf; 352 + 353 + while (p < buf + len) { 354 + int rot; 355 + 356 + if (num_ovls == ofbi->num_overlays) { 357 + r = -EINVAL; 358 + goto out; 359 + } 360 + 361 + rot = simple_strtoul(p, &p, 0); 362 + if (rot < 0 || rot > 3) { 363 + r = -EINVAL; 364 + goto out; 365 + } 366 + 367 + if (ofbi->rotation[num_ovls] != rot) 368 + changed = true; 369 + 370 + rotation[num_ovls++] = rot; 371 + 372 + p++; 373 + } 374 + } 375 + 376 + if (num_ovls != ofbi->num_overlays) { 377 + r = -EINVAL; 378 + goto out; 379 + } 380 + 381 + if (changed) { 382 + for (i = 0; i < num_ovls; ++i) 383 + ofbi->rotation[i] = rotation[i]; 384 + 385 + r = omapfb_apply_changes(fbi, 0); 386 + if (r) 387 + goto out; 388 + 389 + /* FIXME error handling? */ 390 + } 391 + 392 + r = count; 393 + out: 394 + unlock_fb_info(fbi); 395 + 396 + return r; 397 + } 398 + 399 + static ssize_t show_size(struct device *dev, 400 + struct device_attribute *attr, char *buf) 401 + { 402 + struct fb_info *fbi = dev_get_drvdata(dev); 403 + struct omapfb_info *ofbi = FB2OFB(fbi); 404 + 405 + return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size); 406 + } 407 + 408 + static ssize_t store_size(struct device *dev, struct device_attribute *attr, 409 + const char *buf, size_t count) 410 + { 411 + struct fb_info *fbi = dev_get_drvdata(dev); 412 + struct omapfb_info *ofbi = FB2OFB(fbi); 413 + unsigned long size; 414 + int r; 415 + int i; 416 + 417 + size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0)); 418 + 419 + lock_fb_info(fbi); 420 + 421 + for (i = 0; i < ofbi->num_overlays; i++) { 422 + if (ofbi->overlays[i]->info.enabled) { 423 + r = -EBUSY; 424 + goto out; 425 + } 426 + } 427 + 428 + if (size != ofbi->region.size) { 429 + r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type); 430 + if (r) { 431 + dev_err(dev, "realloc fbmem failed\n"); 432 + goto out; 433 + } 434 + } 435 + 436 + r = count; 437 + out: 438 + unlock_fb_info(fbi); 439 + 440 + return r; 441 + } 442 + 443 + static ssize_t show_phys(struct device *dev, 444 + struct device_attribute *attr, char *buf) 445 + { 446 + struct fb_info *fbi = dev_get_drvdata(dev); 447 + struct omapfb_info *ofbi = FB2OFB(fbi); 448 + 449 + return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr); 450 + } 451 + 452 + static ssize_t show_virt(struct device *dev, 453 + struct device_attribute *attr, char *buf) 454 + { 455 + struct fb_info *fbi = dev_get_drvdata(dev); 456 + struct omapfb_info *ofbi = FB2OFB(fbi); 457 + 458 + return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr); 459 + } 460 + 461 + static struct device_attribute omapfb_attrs[] = { 462 + __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type, 463 + store_rotate_type), 464 + __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror), 465 + __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size), 466 + __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays), 467 + __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate, 468 + store_overlays_rotate), 469 + __ATTR(phys_addr, S_IRUGO, show_phys, NULL), 470 + __ATTR(virt_addr, S_IRUGO, show_virt, NULL), 471 + }; 472 + 473 + int omapfb_create_sysfs(struct omapfb2_device *fbdev) 474 + { 475 + int i; 476 + int r; 477 + 478 + DBG("create sysfs for fbs\n"); 479 + for (i = 0; i < fbdev->num_fbs; i++) { 480 + int t; 481 + for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) { 482 + r = device_create_file(fbdev->fbs[i]->dev, 483 + &omapfb_attrs[t]); 484 + 485 + if (r) { 486 + dev_err(fbdev->dev, "failed to create sysfs " 487 + "file\n"); 488 + return r; 489 + } 490 + } 491 + } 492 + 493 + return 0; 494 + } 495 + 496 + void omapfb_remove_sysfs(struct omapfb2_device *fbdev) 497 + { 498 + int i, t; 499 + 500 + DBG("remove sysfs for fbs\n"); 501 + for (i = 0; i < fbdev->num_fbs; i++) { 502 + for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) 503 + device_remove_file(fbdev->fbs[i]->dev, 504 + &omapfb_attrs[t]); 505 + } 506 + } 507 +
+146
drivers/video/omap2/omapfb/omapfb.h
··· 1 + /* 2 + * linux/drivers/video/omap2/omapfb.h 3 + * 4 + * Copyright (C) 2008 Nokia Corporation 5 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 6 + * 7 + * Some code and ideas taken from drivers/video/omap/ driver 8 + * by Imre Deak. 9 + * 10 + * This program is free software; you can redistribute it and/or modify it 11 + * under the terms of the GNU General Public License version 2 as published by 12 + * the Free Software Foundation. 13 + * 14 + * This program is distributed in the hope that it will be useful, but WITHOUT 15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 + * more details. 18 + * 19 + * You should have received a copy of the GNU General Public License along with 20 + * this program. If not, see <http://www.gnu.org/licenses/>. 21 + */ 22 + 23 + #ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__ 24 + #define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__ 25 + 26 + #ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT 27 + #define DEBUG 28 + #endif 29 + 30 + #include <plat/display.h> 31 + 32 + #ifdef DEBUG 33 + extern unsigned int omapfb_debug; 34 + #define DBG(format, ...) \ 35 + if (omapfb_debug) \ 36 + printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__) 37 + #else 38 + #define DBG(format, ...) 39 + #endif 40 + 41 + #define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par)) 42 + 43 + /* max number of overlays to which a framebuffer data can be direct */ 44 + #define OMAPFB_MAX_OVL_PER_FB 3 45 + 46 + struct omapfb2_mem_region { 47 + u32 paddr; 48 + void __iomem *vaddr; 49 + struct vrfb vrfb; 50 + unsigned long size; 51 + u8 type; /* OMAPFB_PLANE_MEM_* */ 52 + bool alloc; /* allocated by the driver */ 53 + bool map; /* kernel mapped by the driver */ 54 + }; 55 + 56 + /* appended to fb_info */ 57 + struct omapfb_info { 58 + int id; 59 + struct omapfb2_mem_region region; 60 + atomic_t map_count; 61 + int num_overlays; 62 + struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; 63 + struct omapfb2_device *fbdev; 64 + enum omap_dss_rotation_type rotation_type; 65 + u8 rotation[OMAPFB_MAX_OVL_PER_FB]; 66 + bool mirror; 67 + }; 68 + 69 + struct omapfb2_device { 70 + struct device *dev; 71 + struct mutex mtx; 72 + 73 + u32 pseudo_palette[17]; 74 + 75 + int state; 76 + 77 + unsigned num_fbs; 78 + struct fb_info *fbs[10]; 79 + 80 + unsigned num_displays; 81 + struct omap_dss_device *displays[10]; 82 + unsigned num_overlays; 83 + struct omap_overlay *overlays[10]; 84 + unsigned num_managers; 85 + struct omap_overlay_manager *managers[10]; 86 + }; 87 + 88 + struct omapfb_colormode { 89 + enum omap_color_mode dssmode; 90 + u32 bits_per_pixel; 91 + u32 nonstd; 92 + struct fb_bitfield red; 93 + struct fb_bitfield green; 94 + struct fb_bitfield blue; 95 + struct fb_bitfield transp; 96 + }; 97 + 98 + void set_fb_fix(struct fb_info *fbi); 99 + int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var); 100 + int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type); 101 + int omapfb_apply_changes(struct fb_info *fbi, int init); 102 + 103 + int omapfb_create_sysfs(struct omapfb2_device *fbdev); 104 + void omapfb_remove_sysfs(struct omapfb2_device *fbdev); 105 + 106 + int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); 107 + 108 + int dss_mode_to_fb_mode(enum omap_color_mode dssmode, 109 + struct fb_var_screeninfo *var); 110 + 111 + /* find the display connected to this fb, if any */ 112 + static inline struct omap_dss_device *fb2display(struct fb_info *fbi) 113 + { 114 + struct omapfb_info *ofbi = FB2OFB(fbi); 115 + int i; 116 + 117 + /* XXX: returns the display connected to first attached overlay */ 118 + for (i = 0; i < ofbi->num_overlays; i++) { 119 + if (ofbi->overlays[i]->manager) 120 + return ofbi->overlays[i]->manager->device; 121 + } 122 + 123 + return NULL; 124 + } 125 + 126 + static inline void omapfb_lock(struct omapfb2_device *fbdev) 127 + { 128 + mutex_lock(&fbdev->mtx); 129 + } 130 + 131 + static inline void omapfb_unlock(struct omapfb2_device *fbdev) 132 + { 133 + mutex_unlock(&fbdev->mtx); 134 + } 135 + 136 + static inline int omapfb_overlay_enable(struct omap_overlay *ovl, 137 + int enable) 138 + { 139 + struct omap_overlay_info info; 140 + 141 + ovl->get_overlay_info(ovl, &info); 142 + info.enabled = enable; 143 + return ovl->set_overlay_info(ovl, &info); 144 + } 145 + 146 + #endif
+54
include/linux/omapfb.h
··· 24 24 #ifndef __LINUX_OMAPFB_H__ 25 25 #define __LINUX_OMAPFB_H__ 26 26 27 + #include <linux/fb.h> 27 28 #include <linux/ioctl.h> 28 29 #include <linux/types.h> 29 30 ··· 51 50 #define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window) 52 51 #define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info) 53 52 #define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info) 53 + #define OMAPFB_WAITFORVSYNC OMAP_IO(57) 54 + #define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read) 55 + #define OMAPFB_GET_OVERLAY_COLORMODE OMAP_IOR(59, struct omapfb_ovl_colormode) 56 + #define OMAPFB_WAITFORGO OMAP_IO(60) 57 + #define OMAPFB_GET_VRAM_INFO OMAP_IOR(61, struct omapfb_vram_info) 58 + #define OMAPFB_SET_TEARSYNC OMAP_IOW(62, struct omapfb_tearsync_info) 54 59 55 60 #define OMAPFB_CAPS_GENERIC_MASK 0x00000fff 56 61 #define OMAPFB_CAPS_LCDC_MASK 0x00fff000 ··· 94 87 OMAPFB_COLOR_CLUT_1BPP, 95 88 OMAPFB_COLOR_RGB444, 96 89 OMAPFB_COLOR_YUY422, 90 + 91 + OMAPFB_COLOR_ARGB16, 92 + OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */ 93 + OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */ 94 + OMAPFB_COLOR_ARGB32, 95 + OMAPFB_COLOR_RGBA32, 96 + OMAPFB_COLOR_RGBX32, 97 97 }; 98 98 99 99 struct omapfb_update_window { ··· 172 158 OMAPFB_MANUAL_UPDATE 173 159 }; 174 160 161 + struct omapfb_memory_read { 162 + __u16 x; 163 + __u16 y; 164 + __u16 w; 165 + __u16 h; 166 + size_t buffer_size; 167 + void __user *buffer; 168 + }; 169 + 170 + struct omapfb_ovl_colormode { 171 + __u8 overlay_idx; 172 + __u8 mode_idx; 173 + __u32 bits_per_pixel; 174 + __u32 nonstd; 175 + struct fb_bitfield red; 176 + struct fb_bitfield green; 177 + struct fb_bitfield blue; 178 + struct fb_bitfield transp; 179 + }; 180 + 181 + struct omapfb_vram_info { 182 + __u32 total; 183 + __u32 free; 184 + __u32 largest_free_block; 185 + __u32 reserved[5]; 186 + }; 187 + 188 + struct omapfb_tearsync_info { 189 + __u8 enabled; 190 + __u8 reserved1[3]; 191 + __u16 line; 192 + __u16 reserved2; 193 + }; 194 + 175 195 #ifdef __KERNEL__ 176 196 177 197 #include <plat/board.h> ··· 221 173 void __iomem *vaddr; 222 174 unsigned long size; 223 175 u8 type; /* OMAPFB_PLANE_MEM_* */ 176 + enum omapfb_color_format format;/* OMAPFB_COLOR_* */ 177 + unsigned format_used:1; /* Must be set when format is set. 178 + * Needed b/c of the badly chosen 0 179 + * base for OMAPFB_COLOR_* values 180 + */ 224 181 unsigned alloc:1; /* allocated by the driver */ 225 182 unsigned map:1; /* kernel mapped by the driver */ 226 183 }; ··· 242 189 }; 243 190 244 191 /* in arch/arm/plat-omap/fb.c */ 192 + extern void omapfb_set_platform_data(struct omapfb_platform_data *data); 245 193 extern void omapfb_set_ctrl_platform_data(void *pdata); 246 194 extern void omapfb_reserve_sdram(void); 247 195