1 /* 2 * Copyright (c) 2006-2009 Red Hat Inc. 3 * Copyright (c) 2006-2008 Intel Corporation 4 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 5 * 6 * DRM framebuffer helper functions 7 * 8 * Permission to use, copy, modify, distribute, and sell this software and its 9 * documentation for any purpose is hereby granted without fee, provided that 10 * the above copyright notice appear in all copies and that both that copyright 11 * notice and this permission notice appear in supporting documentation, and 12 * that the name of the copyright holders not be used in advertising or 13 * publicity pertaining to distribution of the software without specific, 14 * written prior permission. The copyright holders make no representations 15 * about the suitability of this software for any purpose. It is provided "as 16 * is" without express or implied warranty. 17 * 18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24 * OF THIS SOFTWARE. 25 * 26 * Authors: 27 * Dave Airlie <airlied@linux.ie> 28 * Jesse Barnes <jesse.barnes@intel.com> 29 */ 30 31 #include <linux/kernel.h> 32 #include <linux/fb.h> 33 #include <linux/module.h> 34 #include <drm/drmP.h> 35 #include <drm/drm_crtc.h> 36 #include <drm/drm_fb_helper.h> 37 #include <drm/drm_crtc_helper.h> 38 #include <drm/drm_atomic.h> 39 #include <drm/drm_atomic_helper.h> 40 41 static bool drm_fbdev_emulation = true; 42 module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600); 43 MODULE_PARM_DESC(fbdev_emulation, 44 "Enable legacy fbdev emulation [default=true]"); 45 46 static LINUX_LIST_HEAD(kernel_fb_helper_list); 47 48 /** 49 * DOC: fbdev helpers 50 * 51 * The fb helper functions are useful to provide an fbdev on top of a drm kernel 52 * mode setting driver. They can be used mostly independently from the crtc 53 * helper functions used by many drivers to implement the kernel mode setting 54 * interfaces. 55 * 56 * Initialization is done as a four-step process with drm_fb_helper_prepare(), 57 * drm_fb_helper_init(), drm_fb_helper_single_add_all_connectors() and 58 * drm_fb_helper_initial_config(). Drivers with fancier requirements than the 59 * default behaviour can override the third step with their own code. 60 * Teardown is done with drm_fb_helper_fini(). 61 * 62 * At runtime drivers should restore the fbdev console by calling 63 * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback. 64 * They should also notify the fb helper code from updates to the output 65 * configuration by calling drm_fb_helper_hotplug_event(). For easier 66 * integration with the output polling code in drm_crtc_helper.c the modeset 67 * code provides a ->output_poll_changed callback. 68 * 69 * All other functions exported by the fb helper library can be used to 70 * implement the fbdev driver interface by the driver. 71 * 72 * It is possible, though perhaps somewhat tricky, to implement race-free 73 * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare() 74 * helper must be called first to initialize the minimum required to make 75 * hotplug detection work. Drivers also need to make sure to properly set up 76 * the dev->mode_config.funcs member. After calling drm_kms_helper_poll_init() 77 * it is safe to enable interrupts and start processing hotplug events. At the 78 * same time, drivers should initialize all modeset objects such as CRTCs, 79 * encoders and connectors. To finish up the fbdev helper initialization, the 80 * drm_fb_helper_init() function is called. To probe for all attached displays 81 * and set up an initial configuration using the detected hardware, drivers 82 * should call drm_fb_helper_single_add_all_connectors() followed by 83 * drm_fb_helper_initial_config(). 84 */ 85 86 /** 87 * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev 88 * emulation helper 89 * @fb_helper: fbdev initialized with drm_fb_helper_init 90 * 91 * This functions adds all the available connectors for use with the given 92 * fb_helper. This is a separate step to allow drivers to freely assign 93 * connectors to the fbdev, e.g. if some are reserved for special purposes or 94 * not adequate to be used for the fbcon. 95 * 96 * This function is protected against concurrent connector hotadds/removals 97 * using drm_fb_helper_add_one_connector() and 98 * drm_fb_helper_remove_one_connector(). 99 */ 100 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) 101 { 102 struct drm_device *dev = fb_helper->dev; 103 struct drm_connector *connector; 104 int i; 105 106 if (!drm_fbdev_emulation) 107 return 0; 108 109 mutex_lock(&dev->mode_config.mutex); 110 drm_for_each_connector(connector, dev) { 111 struct drm_fb_helper_connector *fb_helper_connector; 112 113 fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); 114 if (!fb_helper_connector) 115 goto fail; 116 117 fb_helper_connector->connector = connector; 118 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; 119 } 120 mutex_unlock(&dev->mode_config.mutex); 121 return 0; 122 fail: 123 for (i = 0; i < fb_helper->connector_count; i++) { 124 kfree(fb_helper->connector_info[i]); 125 fb_helper->connector_info[i] = NULL; 126 } 127 fb_helper->connector_count = 0; 128 mutex_unlock(&dev->mode_config.mutex); 129 130 return -ENOMEM; 131 } 132 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); 133 134 int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector) 135 { 136 struct drm_fb_helper_connector **temp; 137 struct drm_fb_helper_connector *fb_helper_connector; 138 139 if (!drm_fbdev_emulation) 140 return 0; 141 142 WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); 143 if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { 144 temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), M_DRM, M_WAITOK); 145 if (!temp) 146 return -ENOMEM; 147 148 fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1; 149 fb_helper->connector_info = temp; 150 } 151 152 153 fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); 154 if (!fb_helper_connector) 155 return -ENOMEM; 156 157 fb_helper_connector->connector = connector; 158 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; 159 return 0; 160 } 161 EXPORT_SYMBOL(drm_fb_helper_add_one_connector); 162 163 static void remove_from_modeset(struct drm_mode_set *set, 164 struct drm_connector *connector) 165 { 166 int i, j; 167 168 for (i = 0; i < set->num_connectors; i++) { 169 if (set->connectors[i] == connector) 170 break; 171 } 172 173 if (i == set->num_connectors) 174 return; 175 176 for (j = i + 1; j < set->num_connectors; j++) { 177 set->connectors[j - 1] = set->connectors[j]; 178 } 179 set->num_connectors--; 180 181 /* 182 * TODO maybe need to makes sure we set it back to !=NULL somewhere? 183 */ 184 if (set->num_connectors == 0) { 185 set->fb = NULL; 186 drm_mode_destroy(connector->dev, set->mode); 187 set->mode = NULL; 188 } 189 } 190 191 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, 192 struct drm_connector *connector) 193 { 194 struct drm_fb_helper_connector *fb_helper_connector; 195 int i, j; 196 197 if (!drm_fbdev_emulation) 198 return 0; 199 200 WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); 201 202 for (i = 0; i < fb_helper->connector_count; i++) { 203 if (fb_helper->connector_info[i]->connector == connector) 204 break; 205 } 206 207 if (i == fb_helper->connector_count) 208 return -EINVAL; 209 fb_helper_connector = fb_helper->connector_info[i]; 210 211 for (j = i + 1; j < fb_helper->connector_count; j++) { 212 fb_helper->connector_info[j - 1] = fb_helper->connector_info[j]; 213 } 214 fb_helper->connector_count--; 215 kfree(fb_helper_connector); 216 217 /* also cleanup dangling references to the connector: */ 218 for (i = 0; i < fb_helper->crtc_count; i++) 219 remove_from_modeset(&fb_helper->crtc_info[i].mode_set, connector); 220 221 return 0; 222 } 223 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); 224 225 #if 0 226 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) 227 { 228 uint16_t *r_base, *g_base, *b_base; 229 int i; 230 231 if (helper->funcs->gamma_get == NULL) 232 return; 233 234 r_base = crtc->gamma_store; 235 g_base = r_base + crtc->gamma_size; 236 b_base = g_base + crtc->gamma_size; 237 238 for (i = 0; i < crtc->gamma_size; i++) 239 helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i); 240 } 241 242 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) 243 { 244 uint16_t *r_base, *g_base, *b_base; 245 246 if (crtc->funcs->gamma_set == NULL) 247 return; 248 249 r_base = crtc->gamma_store; 250 g_base = r_base + crtc->gamma_size; 251 b_base = g_base + crtc->gamma_size; 252 253 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 254 } 255 #endif 256 257 /** 258 * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter 259 * @info: fbdev registered by the helper 260 */ 261 int drm_fb_helper_debug_enter(struct fb_info *info) 262 { 263 struct drm_fb_helper *helper = info->par; 264 const struct drm_crtc_helper_funcs *funcs; 265 int i; 266 267 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { 268 for (i = 0; i < helper->crtc_count; i++) { 269 struct drm_mode_set *mode_set = 270 &helper->crtc_info[i].mode_set; 271 272 if (!mode_set->crtc->enabled) 273 continue; 274 275 funcs = mode_set->crtc->helper_private; 276 #if 0 277 drm_fb_helper_save_lut_atomic(mode_set->crtc, helper); 278 #endif 279 funcs->mode_set_base_atomic(mode_set->crtc, 280 mode_set->fb, 281 mode_set->x, 282 mode_set->y, 283 ENTER_ATOMIC_MODE_SET); 284 } 285 } 286 287 return 0; 288 } 289 EXPORT_SYMBOL(drm_fb_helper_debug_enter); 290 291 #if 0 292 /* Find the real fb for a given fb helper CRTC */ 293 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) 294 { 295 struct drm_device *dev = crtc->dev; 296 struct drm_crtc *c; 297 298 drm_for_each_crtc(c, dev) { 299 if (crtc->base.id == c->base.id) 300 return c->primary->fb; 301 } 302 303 return NULL; 304 } 305 306 /** 307 * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave 308 * @info: fbdev registered by the helper 309 */ 310 int drm_fb_helper_debug_leave(struct fb_info *info) 311 { 312 struct drm_fb_helper *helper = info->par; 313 struct drm_crtc *crtc; 314 const struct drm_crtc_helper_funcs *funcs; 315 struct drm_framebuffer *fb; 316 int i; 317 318 for (i = 0; i < helper->crtc_count; i++) { 319 struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; 320 crtc = mode_set->crtc; 321 funcs = crtc->helper_private; 322 fb = drm_mode_config_fb(crtc); 323 324 if (!crtc->enabled) 325 continue; 326 327 if (!fb) { 328 DRM_ERROR("no fb to restore??\n"); 329 continue; 330 } 331 332 drm_fb_helper_restore_lut_atomic(mode_set->crtc); 333 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, 334 crtc->y, LEAVE_ATOMIC_MODE_SET); 335 } 336 337 return 0; 338 } 339 EXPORT_SYMBOL(drm_fb_helper_debug_leave); 340 #endif 341 342 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper) 343 { 344 struct drm_device *dev = fb_helper->dev; 345 struct drm_plane *plane; 346 struct drm_atomic_state *state; 347 int i, ret; 348 unsigned plane_mask; 349 350 state = drm_atomic_state_alloc(dev); 351 if (!state) 352 return -ENOMEM; 353 354 state->acquire_ctx = dev->mode_config.acquire_ctx; 355 retry: 356 plane_mask = 0; 357 drm_for_each_plane(plane, dev) { 358 struct drm_plane_state *plane_state; 359 360 plane_state = drm_atomic_get_plane_state(state, plane); 361 if (IS_ERR(plane_state)) { 362 ret = PTR_ERR(plane_state); 363 goto fail; 364 } 365 366 plane_state->rotation = BIT(DRM_ROTATE_0); 367 368 plane->old_fb = plane->fb; 369 plane_mask |= 1 << drm_plane_index(plane); 370 371 /* disable non-primary: */ 372 if (plane->type == DRM_PLANE_TYPE_PRIMARY) 373 continue; 374 375 ret = __drm_atomic_helper_disable_plane(plane, plane_state); 376 if (ret != 0) 377 goto fail; 378 } 379 380 for(i = 0; i < fb_helper->crtc_count; i++) { 381 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 382 383 ret = __drm_atomic_helper_set_config(mode_set, state); 384 if (ret != 0) 385 goto fail; 386 } 387 388 ret = drm_atomic_commit(state); 389 390 fail: 391 drm_atomic_clean_old_fb(dev, plane_mask, ret); 392 393 if (ret == -EDEADLK) 394 goto backoff; 395 396 if (ret != 0) 397 drm_atomic_state_free(state); 398 399 return ret; 400 401 backoff: 402 drm_atomic_state_clear(state); 403 drm_atomic_legacy_backoff(state); 404 405 goto retry; 406 } 407 408 static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) 409 { 410 struct drm_device *dev = fb_helper->dev; 411 struct drm_plane *plane; 412 bool error = false; 413 int i; 414 415 drm_warn_on_modeset_not_all_locked(dev); 416 417 if (fb_helper->atomic) 418 return restore_fbdev_mode_atomic(fb_helper); 419 420 drm_for_each_plane(plane, dev) { 421 if (plane->type != DRM_PLANE_TYPE_PRIMARY) 422 drm_plane_force_disable(plane); 423 424 if (dev->mode_config.rotation_property) { 425 drm_mode_plane_set_obj_prop(plane, 426 dev->mode_config.rotation_property, 427 BIT(DRM_ROTATE_0)); 428 } 429 } 430 431 for (i = 0; i < fb_helper->crtc_count; i++) { 432 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 433 struct drm_crtc *crtc = mode_set->crtc; 434 int ret; 435 436 if (crtc->funcs->cursor_set) { 437 ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); 438 if (ret) 439 error = true; 440 } 441 442 ret = drm_mode_set_config_internal(mode_set); 443 if (ret) 444 error = true; 445 } 446 return error; 447 } 448 449 /** 450 * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration 451 * @fb_helper: fbcon to restore 452 * 453 * This should be called from driver's drm ->lastclose callback 454 * when implementing an fbcon on top of kms using this helper. This ensures that 455 * the user isn't greeted with a black screen when e.g. X dies. 456 * 457 * RETURNS: 458 * Zero if everything went ok, negative error code otherwise. 459 */ 460 int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) 461 { 462 struct drm_device *dev = fb_helper->dev; 463 bool do_delayed; 464 int ret; 465 466 if (!drm_fbdev_emulation) 467 return -ENODEV; 468 469 drm_modeset_lock_all(dev); 470 ret = restore_fbdev_mode(fb_helper); 471 472 do_delayed = fb_helper->delayed_hotplug; 473 if (do_delayed) 474 fb_helper->delayed_hotplug = false; 475 drm_modeset_unlock_all(dev); 476 477 if (do_delayed) 478 drm_fb_helper_hotplug_event(fb_helper); 479 return ret; 480 } 481 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); 482 483 static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) 484 { 485 struct drm_device *dev = fb_helper->dev; 486 struct drm_crtc *crtc; 487 int bound = 0, crtcs_bound = 0; 488 489 /* Sometimes user space wants everything disabled, so don't steal the 490 * display if there's a master. */ 491 #if 0 492 if (dev->primary->master) 493 return false; 494 #endif 495 496 drm_for_each_crtc(crtc, dev) { 497 if (crtc->primary->fb) 498 crtcs_bound++; 499 if (crtc->primary->fb == fb_helper->fb) 500 bound++; 501 } 502 503 if (bound < crtcs_bound) 504 return false; 505 506 return true; 507 } 508 509 #ifdef CONFIG_MAGIC_SYSRQ 510 /* 511 * restore fbcon display for all kms driver's using this helper, used for sysrq 512 * and panic handling. 513 */ 514 static bool drm_fb_helper_force_kernel_mode(void) 515 { 516 bool ret, error = false; 517 struct drm_fb_helper *helper; 518 519 if (list_empty(&kernel_fb_helper_list)) 520 return false; 521 522 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { 523 struct drm_device *dev = helper->dev; 524 525 if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 526 continue; 527 528 drm_modeset_lock_all(dev); 529 ret = restore_fbdev_mode(helper); 530 if (ret) 531 error = true; 532 drm_modeset_unlock_all(dev); 533 } 534 return error; 535 } 536 537 #if 0 538 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) 539 { 540 bool ret; 541 ret = drm_fb_helper_force_kernel_mode(); 542 if (ret == true) 543 DRM_ERROR("Failed to restore crtc configuration\n"); 544 } 545 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn); 546 547 static void drm_fb_helper_sysrq(int dummy1) 548 { 549 schedule_work(&drm_fb_helper_restore_work); 550 } 551 552 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { 553 .handler = drm_fb_helper_sysrq, 554 .help_msg = "force-fb(V)", 555 .action_msg = "Restore framebuffer console", 556 }; 557 #else 558 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { }; 559 #endif 560 #endif 561 562 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) 563 { 564 struct drm_fb_helper *fb_helper = info->par; 565 struct drm_device *dev = fb_helper->dev; 566 struct drm_crtc *crtc; 567 struct drm_connector *connector; 568 int i, j; 569 570 /* 571 * For each CRTC in this fb, turn the connectors on/off. 572 */ 573 drm_modeset_lock_all(dev); 574 if (!drm_fb_helper_is_bound(fb_helper)) { 575 drm_modeset_unlock_all(dev); 576 return; 577 } 578 579 for (i = 0; i < fb_helper->crtc_count; i++) { 580 crtc = fb_helper->crtc_info[i].mode_set.crtc; 581 582 if (!crtc->enabled) 583 continue; 584 585 /* Walk the connectors & encoders on this fb turning them on/off */ 586 for (j = 0; j < fb_helper->connector_count; j++) { 587 connector = fb_helper->connector_info[j]->connector; 588 connector->funcs->dpms(connector, dpms_mode); 589 drm_object_property_set_value(&connector->base, 590 dev->mode_config.dpms_property, dpms_mode); 591 } 592 } 593 drm_modeset_unlock_all(dev); 594 } 595 596 /** 597 * drm_fb_helper_blank - implementation for ->fb_blank 598 * @blank: desired blanking state 599 * @info: fbdev registered by the helper 600 */ 601 int drm_fb_helper_blank(int blank, struct fb_info *info) 602 { 603 #ifdef __DragonFly__ 604 if (panicstr) 605 return -EBUSY; 606 #else 607 if (oops_in_progress) 608 return -EBUSY; 609 #endif 610 611 switch (blank) { 612 /* Display: On; HSync: On, VSync: On */ 613 case FB_BLANK_UNBLANK: 614 drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON); 615 break; 616 #if 0 617 /* Display: Off; HSync: On, VSync: On */ 618 case FB_BLANK_NORMAL: 619 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY); 620 break; 621 /* Display: Off; HSync: Off, VSync: On */ 622 case FB_BLANK_HSYNC_SUSPEND: 623 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY); 624 break; 625 /* Display: Off; HSync: On, VSync: Off */ 626 case FB_BLANK_VSYNC_SUSPEND: 627 drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND); 628 break; 629 #endif 630 /* Display: Off; HSync: Off, VSync: Off */ 631 case FB_BLANK_POWERDOWN: 632 drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF); 633 break; 634 } 635 return 0; 636 } 637 EXPORT_SYMBOL(drm_fb_helper_blank); 638 639 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) 640 { 641 int i; 642 643 for (i = 0; i < helper->connector_count; i++) 644 kfree(helper->connector_info[i]); 645 kfree(helper->connector_info); 646 for (i = 0; i < helper->crtc_count; i++) { 647 kfree(helper->crtc_info[i].mode_set.connectors); 648 if (helper->crtc_info[i].mode_set.mode) 649 drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode); 650 } 651 kfree(helper->crtc_info); 652 } 653 654 /** 655 * drm_fb_helper_prepare - setup a drm_fb_helper structure 656 * @dev: DRM device 657 * @helper: driver-allocated fbdev helper structure to set up 658 * @funcs: pointer to structure of functions associate with this helper 659 * 660 * Sets up the bare minimum to make the framebuffer helper usable. This is 661 * useful to implement race-free initialization of the polling helpers. 662 */ 663 void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, 664 const struct drm_fb_helper_funcs *funcs) 665 { 666 INIT_LIST_HEAD(&helper->kernel_fb_list); 667 helper->funcs = funcs; 668 helper->dev = dev; 669 } 670 EXPORT_SYMBOL(drm_fb_helper_prepare); 671 672 /** 673 * drm_fb_helper_init - initialize a drm_fb_helper structure 674 * @dev: drm device 675 * @fb_helper: driver-allocated fbdev helper structure to initialize 676 * @crtc_count: maximum number of crtcs to support in this fbdev emulation 677 * @max_conn_count: max connector count 678 * 679 * This allocates the structures for the fbdev helper with the given limits. 680 * Note that this won't yet touch the hardware (through the driver interfaces) 681 * nor register the fbdev. This is only done in drm_fb_helper_initial_config() 682 * to allow driver writes more control over the exact init sequence. 683 * 684 * Drivers must call drm_fb_helper_prepare() before calling this function. 685 * 686 * RETURNS: 687 * Zero if everything went ok, nonzero otherwise. 688 */ 689 int drm_fb_helper_init(struct drm_device *dev, 690 struct drm_fb_helper *fb_helper, 691 int crtc_count, int max_conn_count) 692 { 693 struct drm_crtc *crtc; 694 int i; 695 696 if (!drm_fbdev_emulation) 697 return 0; 698 699 if (!max_conn_count) 700 return -EINVAL; 701 702 fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); 703 if (!fb_helper->crtc_info) 704 return -ENOMEM; 705 706 fb_helper->crtc_count = crtc_count; 707 fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); 708 if (!fb_helper->connector_info) { 709 kfree(fb_helper->crtc_info); 710 return -ENOMEM; 711 } 712 fb_helper->connector_info_alloc_count = dev->mode_config.num_connector; 713 fb_helper->connector_count = 0; 714 715 for (i = 0; i < crtc_count; i++) { 716 fb_helper->crtc_info[i].mode_set.connectors = 717 kcalloc(max_conn_count, 718 sizeof(struct drm_connector *), 719 GFP_KERNEL); 720 721 if (!fb_helper->crtc_info[i].mode_set.connectors) 722 goto out_free; 723 fb_helper->crtc_info[i].mode_set.num_connectors = 0; 724 } 725 726 i = 0; 727 drm_for_each_crtc(crtc, dev) { 728 fb_helper->crtc_info[i].mode_set.crtc = crtc; 729 i++; 730 } 731 732 fb_helper->atomic = !!drm_core_check_feature(dev, DRIVER_ATOMIC); 733 734 return 0; 735 out_free: 736 drm_fb_helper_crtc_free(fb_helper); 737 return -ENOMEM; 738 } 739 EXPORT_SYMBOL(drm_fb_helper_init); 740 741 /** 742 * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members 743 * @fb_helper: driver-allocated fbdev helper 744 * 745 * A helper to alloc fb_info and the members cmap and apertures. Called 746 * by the driver within the fb_probe fb_helper callback function. 747 * 748 * RETURNS: 749 * fb_info pointer if things went okay, pointer containing error code 750 * otherwise 751 */ 752 struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper) 753 { 754 struct fb_info *info; 755 756 #ifdef __DragonFly__ 757 info = kzalloc(sizeof(struct fb_info), GFP_KERNEL); 758 #else 759 info = framebuffer_alloc(0, dev); 760 #endif 761 if (!info) 762 return ERR_PTR(-ENOMEM); 763 764 #if 0 765 ret = fb_alloc_cmap(&info->cmap, 256, 0); 766 if (ret) 767 goto err_release; 768 769 info->apertures = alloc_apertures(1); 770 if (!info->apertures) { 771 ret = -ENOMEM; 772 goto err_free_cmap; 773 } 774 #endif 775 776 fb_helper->fbdev = info; 777 778 return info; 779 780 #if 0 781 err_free_cmap: 782 fb_dealloc_cmap(&info->cmap); 783 err_release: 784 framebuffer_release(info); 785 return ERR_PTR(ret); 786 #endif 787 } 788 EXPORT_SYMBOL(drm_fb_helper_alloc_fbi); 789 790 /** 791 * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device 792 * @fb_helper: driver-allocated fbdev helper 793 * 794 * A wrapper around unregister_framebuffer, to release the fb_info 795 * framebuffer device 796 */ 797 void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper) 798 { 799 if (fb_helper && fb_helper->fbdev) 800 unregister_framebuffer(fb_helper->fbdev); 801 } 802 EXPORT_SYMBOL(drm_fb_helper_unregister_fbi); 803 804 /** 805 * drm_fb_helper_release_fbi - dealloc fb_info and its members 806 * @fb_helper: driver-allocated fbdev helper 807 * 808 * A helper to free memory taken by fb_info and the members cmap and 809 * apertures 810 */ 811 void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper) 812 { 813 if (fb_helper) { 814 struct fb_info *info = fb_helper->fbdev; 815 816 if (info) { 817 #ifdef __DragonFly__ 818 kfree(info); 819 #else 820 if (info->cmap.len) 821 fb_dealloc_cmap(&info->cmap); 822 framebuffer_release(info); 823 #endif 824 } 825 826 fb_helper->fbdev = NULL; 827 } 828 } 829 EXPORT_SYMBOL(drm_fb_helper_release_fbi); 830 831 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) 832 { 833 if (!drm_fbdev_emulation) 834 return; 835 836 if (!list_empty(&fb_helper->kernel_fb_list)) { 837 list_del(&fb_helper->kernel_fb_list); 838 if (list_empty(&kernel_fb_helper_list)) { 839 #if 0 840 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 841 #endif 842 } 843 } 844 845 drm_fb_helper_crtc_free(fb_helper); 846 847 } 848 EXPORT_SYMBOL(drm_fb_helper_fini); 849 850 #if 0 851 /** 852 * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer 853 * @fb_helper: driver-allocated fbdev helper 854 * 855 * A wrapper around unlink_framebuffer implemented by fbdev core 856 */ 857 void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) 858 { 859 if (fb_helper && fb_helper->fbdev) 860 unlink_framebuffer(fb_helper->fbdev); 861 } 862 EXPORT_SYMBOL(drm_fb_helper_unlink_fbi); 863 864 /** 865 * drm_fb_helper_sys_read - wrapper around fb_sys_read 866 * @info: fb_info struct pointer 867 * @buf: userspace buffer to read from framebuffer memory 868 * @count: number of bytes to read from framebuffer memory 869 * @ppos: read offset within framebuffer memory 870 * 871 * A wrapper around fb_sys_read implemented by fbdev core 872 */ 873 ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, 874 size_t count, loff_t *ppos) 875 { 876 return fb_sys_read(info, buf, count, ppos); 877 } 878 EXPORT_SYMBOL(drm_fb_helper_sys_read); 879 880 /** 881 * drm_fb_helper_sys_write - wrapper around fb_sys_write 882 * @info: fb_info struct pointer 883 * @buf: userspace buffer to write to framebuffer memory 884 * @count: number of bytes to write to framebuffer memory 885 * @ppos: write offset within framebuffer memory 886 * 887 * A wrapper around fb_sys_write implemented by fbdev core 888 */ 889 ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, 890 size_t count, loff_t *ppos) 891 { 892 return fb_sys_write(info, buf, count, ppos); 893 } 894 EXPORT_SYMBOL(drm_fb_helper_sys_write); 895 896 /** 897 * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect 898 * @info: fbdev registered by the helper 899 * @rect: info about rectangle to fill 900 * 901 * A wrapper around sys_fillrect implemented by fbdev core 902 */ 903 void drm_fb_helper_sys_fillrect(struct fb_info *info, 904 const struct fb_fillrect *rect) 905 { 906 sys_fillrect(info, rect); 907 } 908 EXPORT_SYMBOL(drm_fb_helper_sys_fillrect); 909 910 /** 911 * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea 912 * @info: fbdev registered by the helper 913 * @area: info about area to copy 914 * 915 * A wrapper around sys_copyarea implemented by fbdev core 916 */ 917 void drm_fb_helper_sys_copyarea(struct fb_info *info, 918 const struct fb_copyarea *area) 919 { 920 sys_copyarea(info, area); 921 } 922 EXPORT_SYMBOL(drm_fb_helper_sys_copyarea); 923 924 /** 925 * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit 926 * @info: fbdev registered by the helper 927 * @image: info about image to blit 928 * 929 * A wrapper around sys_imageblit implemented by fbdev core 930 */ 931 void drm_fb_helper_sys_imageblit(struct fb_info *info, 932 const struct fb_image *image) 933 { 934 sys_imageblit(info, image); 935 } 936 EXPORT_SYMBOL(drm_fb_helper_sys_imageblit); 937 938 /** 939 * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect 940 * @info: fbdev registered by the helper 941 * @rect: info about rectangle to fill 942 * 943 * A wrapper around cfb_imageblit implemented by fbdev core 944 */ 945 void drm_fb_helper_cfb_fillrect(struct fb_info *info, 946 const struct fb_fillrect *rect) 947 { 948 cfb_fillrect(info, rect); 949 } 950 EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect); 951 952 /** 953 * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea 954 * @info: fbdev registered by the helper 955 * @area: info about area to copy 956 * 957 * A wrapper around cfb_copyarea implemented by fbdev core 958 */ 959 void drm_fb_helper_cfb_copyarea(struct fb_info *info, 960 const struct fb_copyarea *area) 961 { 962 cfb_copyarea(info, area); 963 } 964 EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea); 965 966 /** 967 * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit 968 * @info: fbdev registered by the helper 969 * @image: info about image to blit 970 * 971 * A wrapper around cfb_imageblit implemented by fbdev core 972 */ 973 void drm_fb_helper_cfb_imageblit(struct fb_info *info, 974 const struct fb_image *image) 975 { 976 cfb_imageblit(info, image); 977 } 978 EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); 979 980 /** 981 * drm_fb_helper_set_suspend - wrapper around fb_set_suspend 982 * @fb_helper: driver-allocated fbdev helper 983 * @state: desired state, zero to resume, non-zero to suspend 984 * 985 * A wrapper around fb_set_suspend implemented by fbdev core 986 */ 987 void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state) 988 { 989 if (fb_helper && fb_helper->fbdev) 990 fb_set_suspend(fb_helper->fbdev, state); 991 } 992 EXPORT_SYMBOL(drm_fb_helper_set_suspend); 993 994 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, 995 u16 blue, u16 regno, struct fb_info *info) 996 { 997 struct drm_fb_helper *fb_helper = info->par; 998 struct drm_framebuffer *fb = fb_helper->fb; 999 int pindex; 1000 1001 if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 1002 u32 *palette; 1003 u32 value; 1004 /* place color in psuedopalette */ 1005 if (regno > 16) 1006 return -EINVAL; 1007 palette = (u32 *)info->pseudo_palette; 1008 red >>= (16 - info->var.red.length); 1009 green >>= (16 - info->var.green.length); 1010 blue >>= (16 - info->var.blue.length); 1011 value = (red << info->var.red.offset) | 1012 (green << info->var.green.offset) | 1013 (blue << info->var.blue.offset); 1014 if (info->var.transp.length > 0) { 1015 u32 mask = (1 << info->var.transp.length) - 1; 1016 mask <<= info->var.transp.offset; 1017 value |= mask; 1018 } 1019 palette[regno] = value; 1020 return 0; 1021 } 1022 1023 /* 1024 * The driver really shouldn't advertise pseudo/directcolor 1025 * visuals if it can't deal with the palette. 1026 */ 1027 if (WARN_ON(!fb_helper->funcs->gamma_set || 1028 !fb_helper->funcs->gamma_get)) 1029 return -EINVAL; 1030 1031 pindex = regno; 1032 1033 if (fb->bits_per_pixel == 16) { 1034 pindex = regno << 3; 1035 1036 if (fb->depth == 16 && regno > 63) 1037 return -EINVAL; 1038 if (fb->depth == 15 && regno > 31) 1039 return -EINVAL; 1040 1041 if (fb->depth == 16) { 1042 u16 r, g, b; 1043 int i; 1044 if (regno < 32) { 1045 for (i = 0; i < 8; i++) 1046 fb_helper->funcs->gamma_set(crtc, red, 1047 green, blue, pindex + i); 1048 } 1049 1050 fb_helper->funcs->gamma_get(crtc, &r, 1051 &g, &b, 1052 pindex >> 1); 1053 1054 for (i = 0; i < 4; i++) 1055 fb_helper->funcs->gamma_set(crtc, r, 1056 green, b, 1057 (pindex >> 1) + i); 1058 } 1059 } 1060 1061 if (fb->depth != 16) 1062 fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); 1063 return 0; 1064 } 1065 1066 /** 1067 * drm_fb_helper_setcmap - implementation for ->fb_setcmap 1068 * @cmap: cmap to set 1069 * @info: fbdev registered by the helper 1070 */ 1071 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) 1072 { 1073 struct drm_fb_helper *fb_helper = info->par; 1074 struct drm_device *dev = fb_helper->dev; 1075 const struct drm_crtc_helper_funcs *crtc_funcs; 1076 u16 *red, *green, *blue, *transp; 1077 struct drm_crtc *crtc; 1078 int i, j, rc = 0; 1079 int start; 1080 1081 if (oops_in_progress) 1082 return -EBUSY; 1083 1084 drm_modeset_lock_all(dev); 1085 if (!drm_fb_helper_is_bound(fb_helper)) { 1086 drm_modeset_unlock_all(dev); 1087 return -EBUSY; 1088 } 1089 1090 for (i = 0; i < fb_helper->crtc_count; i++) { 1091 crtc = fb_helper->crtc_info[i].mode_set.crtc; 1092 crtc_funcs = crtc->helper_private; 1093 1094 red = cmap->red; 1095 green = cmap->green; 1096 blue = cmap->blue; 1097 transp = cmap->transp; 1098 start = cmap->start; 1099 1100 for (j = 0; j < cmap->len; j++) { 1101 u16 hred, hgreen, hblue, htransp = 0xffff; 1102 1103 hred = *red++; 1104 hgreen = *green++; 1105 hblue = *blue++; 1106 1107 if (transp) 1108 htransp = *transp++; 1109 1110 rc = setcolreg(crtc, hred, hgreen, hblue, start++, info); 1111 if (rc) 1112 goto out; 1113 } 1114 if (crtc_funcs->load_lut) 1115 crtc_funcs->load_lut(crtc); 1116 } 1117 out: 1118 drm_modeset_unlock_all(dev); 1119 return rc; 1120 } 1121 EXPORT_SYMBOL(drm_fb_helper_setcmap); 1122 1123 /** 1124 * drm_fb_helper_check_var - implementation for ->fb_check_var 1125 * @var: screeninfo to check 1126 * @info: fbdev registered by the helper 1127 */ 1128 int drm_fb_helper_check_var(struct fb_var_screeninfo *var, 1129 struct fb_info *info) 1130 { 1131 struct drm_fb_helper *fb_helper = info->par; 1132 struct drm_framebuffer *fb = fb_helper->fb; 1133 int depth; 1134 1135 if (var->pixclock != 0 || in_dbg_master()) 1136 return -EINVAL; 1137 1138 /* Need to resize the fb object !!! */ 1139 if (var->bits_per_pixel > fb->bits_per_pixel || 1140 var->xres > fb->width || var->yres > fb->height || 1141 var->xres_virtual > fb->width || var->yres_virtual > fb->height) { 1142 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " 1143 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", 1144 var->xres, var->yres, var->bits_per_pixel, 1145 var->xres_virtual, var->yres_virtual, 1146 fb->width, fb->height, fb->bits_per_pixel); 1147 return -EINVAL; 1148 } 1149 1150 switch (var->bits_per_pixel) { 1151 case 16: 1152 depth = (var->green.length == 6) ? 16 : 15; 1153 break; 1154 case 32: 1155 depth = (var->transp.length > 0) ? 32 : 24; 1156 break; 1157 default: 1158 depth = var->bits_per_pixel; 1159 break; 1160 } 1161 1162 switch (depth) { 1163 case 8: 1164 var->red.offset = 0; 1165 var->green.offset = 0; 1166 var->blue.offset = 0; 1167 var->red.length = 8; 1168 var->green.length = 8; 1169 var->blue.length = 8; 1170 var->transp.length = 0; 1171 var->transp.offset = 0; 1172 break; 1173 case 15: 1174 var->red.offset = 10; 1175 var->green.offset = 5; 1176 var->blue.offset = 0; 1177 var->red.length = 5; 1178 var->green.length = 5; 1179 var->blue.length = 5; 1180 var->transp.length = 1; 1181 var->transp.offset = 15; 1182 break; 1183 case 16: 1184 var->red.offset = 11; 1185 var->green.offset = 5; 1186 var->blue.offset = 0; 1187 var->red.length = 5; 1188 var->green.length = 6; 1189 var->blue.length = 5; 1190 var->transp.length = 0; 1191 var->transp.offset = 0; 1192 break; 1193 case 24: 1194 var->red.offset = 16; 1195 var->green.offset = 8; 1196 var->blue.offset = 0; 1197 var->red.length = 8; 1198 var->green.length = 8; 1199 var->blue.length = 8; 1200 var->transp.length = 0; 1201 var->transp.offset = 0; 1202 break; 1203 case 32: 1204 var->red.offset = 16; 1205 var->green.offset = 8; 1206 var->blue.offset = 0; 1207 var->red.length = 8; 1208 var->green.length = 8; 1209 var->blue.length = 8; 1210 var->transp.length = 8; 1211 var->transp.offset = 24; 1212 break; 1213 default: 1214 return -EINVAL; 1215 } 1216 return 0; 1217 } 1218 EXPORT_SYMBOL(drm_fb_helper_check_var); 1219 #endif 1220 1221 /** 1222 * drm_fb_helper_set_par - implementation for ->fb_set_par 1223 * @info: fbdev registered by the helper 1224 * 1225 * This will let fbcon do the mode init and is called at initialization time by 1226 * the fbdev core when registering the driver, and later on through the hotplug 1227 * callback. 1228 */ 1229 int drm_fb_helper_set_par(struct fb_info *info) 1230 { 1231 struct drm_fb_helper *fb_helper = info->par; 1232 #if 0 1233 struct fb_var_screeninfo *var = &info->var; 1234 #endif 1235 1236 #ifdef __DragonFly__ 1237 if (panicstr) 1238 return -EBUSY; 1239 #else 1240 if (oops_in_progress) 1241 return -EBUSY; 1242 #endif 1243 1244 #if 0 1245 if (var->pixclock != 0) { 1246 DRM_ERROR("PIXEL CLOCK SET\n"); 1247 return -EINVAL; 1248 } 1249 #endif 1250 1251 drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); 1252 1253 return 0; 1254 } 1255 EXPORT_SYMBOL(drm_fb_helper_set_par); 1256 1257 #if 0 1258 static int pan_display_atomic(struct fb_var_screeninfo *var, 1259 struct fb_info *info) 1260 { 1261 struct drm_fb_helper *fb_helper = info->par; 1262 struct drm_device *dev = fb_helper->dev; 1263 struct drm_atomic_state *state; 1264 struct drm_plane *plane; 1265 int i, ret; 1266 unsigned plane_mask; 1267 1268 state = drm_atomic_state_alloc(dev); 1269 if (!state) 1270 return -ENOMEM; 1271 1272 state->acquire_ctx = dev->mode_config.acquire_ctx; 1273 retry: 1274 plane_mask = 0; 1275 for(i = 0; i < fb_helper->crtc_count; i++) { 1276 struct drm_mode_set *mode_set; 1277 1278 mode_set = &fb_helper->crtc_info[i].mode_set; 1279 1280 mode_set->x = var->xoffset; 1281 mode_set->y = var->yoffset; 1282 1283 ret = __drm_atomic_helper_set_config(mode_set, state); 1284 if (ret != 0) 1285 goto fail; 1286 1287 plane = mode_set->crtc->primary; 1288 plane_mask |= (1 << drm_plane_index(plane)); 1289 plane->old_fb = plane->fb; 1290 } 1291 1292 ret = drm_atomic_commit(state); 1293 if (ret != 0) 1294 goto fail; 1295 1296 info->var.xoffset = var->xoffset; 1297 info->var.yoffset = var->yoffset; 1298 1299 1300 fail: 1301 drm_atomic_clean_old_fb(dev, plane_mask, ret); 1302 1303 if (ret == -EDEADLK) 1304 goto backoff; 1305 1306 if (ret != 0) 1307 drm_atomic_state_free(state); 1308 1309 return ret; 1310 1311 backoff: 1312 drm_atomic_state_clear(state); 1313 drm_atomic_legacy_backoff(state); 1314 1315 goto retry; 1316 } 1317 1318 /** 1319 * drm_fb_helper_pan_display - implementation for ->fb_pan_display 1320 * @var: updated screen information 1321 * @info: fbdev registered by the helper 1322 */ 1323 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, 1324 struct fb_info *info) 1325 { 1326 struct drm_fb_helper *fb_helper = info->par; 1327 struct drm_device *dev = fb_helper->dev; 1328 struct drm_mode_set *modeset; 1329 int ret = 0; 1330 int i; 1331 1332 if (oops_in_progress) 1333 return -EBUSY; 1334 1335 drm_modeset_lock_all(dev); 1336 if (!drm_fb_helper_is_bound(fb_helper)) { 1337 drm_modeset_unlock_all(dev); 1338 return -EBUSY; 1339 } 1340 1341 if (fb_helper->atomic) { 1342 ret = pan_display_atomic(var, info); 1343 goto unlock; 1344 } 1345 1346 for (i = 0; i < fb_helper->crtc_count; i++) { 1347 modeset = &fb_helper->crtc_info[i].mode_set; 1348 1349 modeset->x = var->xoffset; 1350 modeset->y = var->yoffset; 1351 1352 if (modeset->num_connectors) { 1353 ret = drm_mode_set_config_internal(modeset); 1354 if (!ret) { 1355 info->var.xoffset = var->xoffset; 1356 info->var.yoffset = var->yoffset; 1357 } 1358 } 1359 } 1360 unlock: 1361 drm_modeset_unlock_all(dev); 1362 return ret; 1363 } 1364 EXPORT_SYMBOL(drm_fb_helper_pan_display); 1365 #endif 1366 1367 /* 1368 * Allocates the backing storage and sets up the fbdev info structure through 1369 * the ->fb_probe callback and then registers the fbdev and sets up the panic 1370 * notifier. 1371 */ 1372 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, 1373 int preferred_bpp) 1374 { 1375 int ret = 0; 1376 int crtc_count = 0; 1377 int i; 1378 struct fb_info *info; 1379 struct drm_fb_helper_surface_size sizes; 1380 int gamma_size = 0; 1381 #ifdef __DragonFly__ 1382 int kms_console = 1; 1383 #endif 1384 1385 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); 1386 sizes.surface_depth = 24; 1387 sizes.surface_bpp = 32; 1388 sizes.fb_width = (unsigned)-1; 1389 sizes.fb_height = (unsigned)-1; 1390 1391 /* if driver picks 8 or 16 by default use that 1392 for both depth/bpp */ 1393 if (preferred_bpp != sizes.surface_bpp) 1394 sizes.surface_depth = sizes.surface_bpp = preferred_bpp; 1395 1396 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 1397 for (i = 0; i < fb_helper->connector_count; i++) { 1398 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; 1399 struct drm_cmdline_mode *cmdline_mode; 1400 1401 cmdline_mode = &fb_helper_conn->connector->cmdline_mode; 1402 1403 if (cmdline_mode->bpp_specified) { 1404 switch (cmdline_mode->bpp) { 1405 case 8: 1406 sizes.surface_depth = sizes.surface_bpp = 8; 1407 break; 1408 case 15: 1409 sizes.surface_depth = 15; 1410 sizes.surface_bpp = 16; 1411 break; 1412 case 16: 1413 sizes.surface_depth = sizes.surface_bpp = 16; 1414 break; 1415 case 24: 1416 sizes.surface_depth = sizes.surface_bpp = 24; 1417 break; 1418 case 32: 1419 sizes.surface_depth = 24; 1420 sizes.surface_bpp = 32; 1421 break; 1422 } 1423 break; 1424 } 1425 } 1426 1427 crtc_count = 0; 1428 for (i = 0; i < fb_helper->crtc_count; i++) { 1429 struct drm_display_mode *desired_mode; 1430 struct drm_mode_set *mode_set; 1431 int x, y, j; 1432 /* in case of tile group, are we the last tile vert or horiz? 1433 * If no tile group you are always the last one both vertically 1434 * and horizontally 1435 */ 1436 bool lastv = true, lasth = true; 1437 1438 desired_mode = fb_helper->crtc_info[i].desired_mode; 1439 mode_set = &fb_helper->crtc_info[i].mode_set; 1440 1441 if (!desired_mode) 1442 continue; 1443 1444 crtc_count++; 1445 1446 x = fb_helper->crtc_info[i].x; 1447 y = fb_helper->crtc_info[i].y; 1448 1449 if (gamma_size == 0) 1450 gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; 1451 1452 sizes.surface_width = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width); 1453 sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height); 1454 1455 for (j = 0; j < mode_set->num_connectors; j++) { 1456 struct drm_connector *connector = mode_set->connectors[j]; 1457 if (connector->has_tile) { 1458 lasth = (connector->tile_h_loc == (connector->num_h_tile - 1)); 1459 lastv = (connector->tile_v_loc == (connector->num_v_tile - 1)); 1460 /* cloning to multiple tiles is just crazy-talk, so: */ 1461 break; 1462 } 1463 } 1464 1465 if (lasth) 1466 sizes.fb_width = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width); 1467 if (lastv) 1468 sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height); 1469 } 1470 1471 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { 1472 /* hmm everyone went away - assume VGA cable just fell out 1473 and will come back later. */ 1474 DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); 1475 sizes.fb_width = sizes.surface_width = 1024; 1476 sizes.fb_height = sizes.surface_height = 768; 1477 } 1478 1479 /* push down into drivers */ 1480 ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); 1481 if (ret < 0) 1482 return ret; 1483 1484 info = fb_helper->fbdev; 1485 1486 /* 1487 * Set the fb pointer - usually drm_setup_crtcs does this for hotplug 1488 * events, but at init time drm_setup_crtcs needs to be called before 1489 * the fb is allocated (since we need to figure out the desired size of 1490 * the fb before we can allocate it ...). Hence we need to fix things up 1491 * here again. 1492 */ 1493 for (i = 0; i < fb_helper->crtc_count; i++) 1494 if (fb_helper->crtc_info[i].mode_set.num_connectors) 1495 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; 1496 1497 #ifdef __DragonFly__ 1498 TUNABLE_INT_FETCH("kern.kms_console", &kms_console); 1499 if (kms_console) { 1500 if (register_framebuffer(info) < 0) 1501 return -EINVAL; 1502 1503 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); 1504 } 1505 #else 1506 info->var.pixclock = 0; 1507 if (register_framebuffer(info) < 0) 1508 return -EINVAL; 1509 1510 dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", 1511 info->node, info->fix.id); 1512 1513 if (list_empty(&kernel_fb_helper_list)) { 1514 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 1515 } 1516 1517 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); 1518 #endif 1519 1520 return 0; 1521 } 1522 1523 #if 0 1524 /** 1525 * drm_fb_helper_fill_fix - initializes fixed fbdev information 1526 * @info: fbdev registered by the helper 1527 * @pitch: desired pitch 1528 * @depth: desired depth 1529 * 1530 * Helper to fill in the fixed fbdev information useful for a non-accelerated 1531 * fbdev emulations. Drivers which support acceleration methods which impose 1532 * additional constraints need to set up their own limits. 1533 * 1534 * Drivers should call this (or their equivalent setup code) from their 1535 * ->fb_probe callback. 1536 */ 1537 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 1538 uint32_t depth) 1539 { 1540 info->fix.type = FB_TYPE_PACKED_PIXELS; 1541 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : 1542 FB_VISUAL_TRUECOLOR; 1543 info->fix.mmio_start = 0; 1544 info->fix.mmio_len = 0; 1545 info->fix.type_aux = 0; 1546 info->fix.xpanstep = 1; /* doing it in hw */ 1547 info->fix.ypanstep = 1; /* doing it in hw */ 1548 info->fix.ywrapstep = 0; 1549 info->fix.accel = FB_ACCEL_NONE; 1550 1551 info->fix.line_length = pitch; 1552 return; 1553 } 1554 EXPORT_SYMBOL(drm_fb_helper_fill_fix); 1555 1556 /** 1557 * drm_fb_helper_fill_var - initalizes variable fbdev information 1558 * @info: fbdev instance to set up 1559 * @fb_helper: fb helper instance to use as template 1560 * @fb_width: desired fb width 1561 * @fb_height: desired fb height 1562 * 1563 * Sets up the variable fbdev metainformation from the given fb helper instance 1564 * and the drm framebuffer allocated in fb_helper->fb. 1565 * 1566 * Drivers should call this (or their equivalent setup code) from their 1567 * ->fb_probe callback after having allocated the fbdev backing 1568 * storage framebuffer. 1569 */ 1570 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, 1571 uint32_t fb_width, uint32_t fb_height) 1572 { 1573 struct drm_framebuffer *fb = fb_helper->fb; 1574 info->pseudo_palette = fb_helper->pseudo_palette; 1575 info->var.xres_virtual = fb->width; 1576 info->var.yres_virtual = fb->height; 1577 info->var.bits_per_pixel = fb->bits_per_pixel; 1578 info->var.accel_flags = FB_ACCELF_TEXT; 1579 info->var.xoffset = 0; 1580 info->var.yoffset = 0; 1581 info->var.activate = FB_ACTIVATE_NOW; 1582 info->var.height = -1; 1583 info->var.width = -1; 1584 1585 switch (fb->depth) { 1586 case 8: 1587 info->var.red.offset = 0; 1588 info->var.green.offset = 0; 1589 info->var.blue.offset = 0; 1590 info->var.red.length = 8; /* 8bit DAC */ 1591 info->var.green.length = 8; 1592 info->var.blue.length = 8; 1593 info->var.transp.offset = 0; 1594 info->var.transp.length = 0; 1595 break; 1596 case 15: 1597 info->var.red.offset = 10; 1598 info->var.green.offset = 5; 1599 info->var.blue.offset = 0; 1600 info->var.red.length = 5; 1601 info->var.green.length = 5; 1602 info->var.blue.length = 5; 1603 info->var.transp.offset = 15; 1604 info->var.transp.length = 1; 1605 break; 1606 case 16: 1607 info->var.red.offset = 11; 1608 info->var.green.offset = 5; 1609 info->var.blue.offset = 0; 1610 info->var.red.length = 5; 1611 info->var.green.length = 6; 1612 info->var.blue.length = 5; 1613 info->var.transp.offset = 0; 1614 break; 1615 case 24: 1616 info->var.red.offset = 16; 1617 info->var.green.offset = 8; 1618 info->var.blue.offset = 0; 1619 info->var.red.length = 8; 1620 info->var.green.length = 8; 1621 info->var.blue.length = 8; 1622 info->var.transp.offset = 0; 1623 info->var.transp.length = 0; 1624 break; 1625 case 32: 1626 info->var.red.offset = 16; 1627 info->var.green.offset = 8; 1628 info->var.blue.offset = 0; 1629 info->var.red.length = 8; 1630 info->var.green.length = 8; 1631 info->var.blue.length = 8; 1632 info->var.transp.offset = 24; 1633 info->var.transp.length = 8; 1634 break; 1635 default: 1636 break; 1637 } 1638 1639 info->var.xres = fb_width; 1640 info->var.yres = fb_height; 1641 } 1642 EXPORT_SYMBOL(drm_fb_helper_fill_var); 1643 #endif 1644 1645 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, 1646 uint32_t maxX, 1647 uint32_t maxY) 1648 { 1649 struct drm_connector *connector; 1650 int count = 0; 1651 int i; 1652 1653 for (i = 0; i < fb_helper->connector_count; i++) { 1654 connector = fb_helper->connector_info[i]->connector; 1655 count += connector->funcs->fill_modes(connector, maxX, maxY); 1656 } 1657 1658 return count; 1659 } 1660 1661 struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) 1662 { 1663 struct drm_display_mode *mode; 1664 1665 list_for_each_entry(mode, &fb_connector->connector->modes, head) { 1666 if (mode->hdisplay > width || 1667 mode->vdisplay > height) 1668 continue; 1669 if (mode->type & DRM_MODE_TYPE_PREFERRED) 1670 return mode; 1671 } 1672 return NULL; 1673 } 1674 EXPORT_SYMBOL(drm_has_preferred_mode); 1675 1676 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) 1677 { 1678 return fb_connector->connector->cmdline_mode.specified; 1679 } 1680 1681 struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, 1682 int width, int height) 1683 { 1684 struct drm_cmdline_mode *cmdline_mode; 1685 struct drm_display_mode *mode; 1686 bool prefer_non_interlace; 1687 1688 cmdline_mode = &fb_helper_conn->connector->cmdline_mode; 1689 if (cmdline_mode->specified == false) 1690 return NULL; 1691 1692 /* attempt to find a matching mode in the list of modes 1693 * we have gotten so far, if not add a CVT mode that conforms 1694 */ 1695 if (cmdline_mode->rb || cmdline_mode->margins) 1696 goto create_mode; 1697 1698 prefer_non_interlace = !cmdline_mode->interlace; 1699 again: 1700 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { 1701 /* check width/height */ 1702 if (mode->hdisplay != cmdline_mode->xres || 1703 mode->vdisplay != cmdline_mode->yres) 1704 continue; 1705 1706 if (cmdline_mode->refresh_specified) { 1707 if (mode->vrefresh != cmdline_mode->refresh) 1708 continue; 1709 } 1710 1711 if (cmdline_mode->interlace) { 1712 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) 1713 continue; 1714 } else if (prefer_non_interlace) { 1715 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1716 continue; 1717 } 1718 return mode; 1719 } 1720 1721 if (prefer_non_interlace) { 1722 prefer_non_interlace = false; 1723 goto again; 1724 } 1725 1726 create_mode: 1727 mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, 1728 cmdline_mode); 1729 list_add(&mode->head, &fb_helper_conn->connector->modes); 1730 return mode; 1731 } 1732 EXPORT_SYMBOL(drm_pick_cmdline_mode); 1733 1734 static bool drm_connector_enabled(struct drm_connector *connector, bool strict) 1735 { 1736 bool enable; 1737 1738 if (strict) 1739 enable = connector->status == connector_status_connected; 1740 else 1741 enable = connector->status != connector_status_disconnected; 1742 1743 return enable; 1744 } 1745 1746 static void drm_enable_connectors(struct drm_fb_helper *fb_helper, 1747 bool *enabled) 1748 { 1749 bool any_enabled = false; 1750 struct drm_connector *connector; 1751 int i = 0; 1752 1753 for (i = 0; i < fb_helper->connector_count; i++) { 1754 connector = fb_helper->connector_info[i]->connector; 1755 enabled[i] = drm_connector_enabled(connector, true); 1756 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, 1757 enabled[i] ? "yes" : "no"); 1758 any_enabled |= enabled[i]; 1759 } 1760 1761 if (any_enabled) 1762 return; 1763 1764 for (i = 0; i < fb_helper->connector_count; i++) { 1765 connector = fb_helper->connector_info[i]->connector; 1766 enabled[i] = drm_connector_enabled(connector, false); 1767 } 1768 } 1769 1770 static bool drm_target_cloned(struct drm_fb_helper *fb_helper, 1771 struct drm_display_mode **modes, 1772 struct drm_fb_offset *offsets, 1773 bool *enabled, int width, int height) 1774 { 1775 int count, i, j; 1776 bool can_clone = false; 1777 struct drm_fb_helper_connector *fb_helper_conn; 1778 struct drm_display_mode *dmt_mode, *mode; 1779 1780 /* only contemplate cloning in the single crtc case */ 1781 if (fb_helper->crtc_count > 1) 1782 return false; 1783 1784 count = 0; 1785 for (i = 0; i < fb_helper->connector_count; i++) { 1786 if (enabled[i]) 1787 count++; 1788 } 1789 1790 /* only contemplate cloning if more than one connector is enabled */ 1791 if (count <= 1) 1792 return false; 1793 1794 /* check the command line or if nothing common pick 1024x768 */ 1795 can_clone = true; 1796 for (i = 0; i < fb_helper->connector_count; i++) { 1797 if (!enabled[i]) 1798 continue; 1799 fb_helper_conn = fb_helper->connector_info[i]; 1800 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); 1801 if (!modes[i]) { 1802 can_clone = false; 1803 break; 1804 } 1805 for (j = 0; j < i; j++) { 1806 if (!enabled[j]) 1807 continue; 1808 if (!drm_mode_equal(modes[j], modes[i])) 1809 can_clone = false; 1810 } 1811 } 1812 1813 if (can_clone) { 1814 DRM_DEBUG_KMS("can clone using command line\n"); 1815 return true; 1816 } 1817 1818 /* try and find a 1024x768 mode on each connector */ 1819 can_clone = true; 1820 dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false); 1821 1822 for (i = 0; i < fb_helper->connector_count; i++) { 1823 1824 if (!enabled[i]) 1825 continue; 1826 1827 fb_helper_conn = fb_helper->connector_info[i]; 1828 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { 1829 if (drm_mode_equal(mode, dmt_mode)) 1830 modes[i] = mode; 1831 } 1832 if (!modes[i]) 1833 can_clone = false; 1834 } 1835 1836 if (can_clone) { 1837 DRM_DEBUG_KMS("can clone using 1024x768\n"); 1838 return true; 1839 } 1840 DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); 1841 return false; 1842 } 1843 1844 static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper, 1845 struct drm_display_mode **modes, 1846 struct drm_fb_offset *offsets, 1847 int idx, 1848 int h_idx, int v_idx) 1849 { 1850 struct drm_fb_helper_connector *fb_helper_conn; 1851 int i; 1852 int hoffset = 0, voffset = 0; 1853 1854 for (i = 0; i < fb_helper->connector_count; i++) { 1855 fb_helper_conn = fb_helper->connector_info[i]; 1856 if (!fb_helper_conn->connector->has_tile) 1857 continue; 1858 1859 if (!modes[i] && (h_idx || v_idx)) { 1860 DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, 1861 fb_helper_conn->connector->base.id); 1862 continue; 1863 } 1864 if (fb_helper_conn->connector->tile_h_loc < h_idx) 1865 hoffset += modes[i]->hdisplay; 1866 1867 if (fb_helper_conn->connector->tile_v_loc < v_idx) 1868 voffset += modes[i]->vdisplay; 1869 } 1870 offsets[idx].x = hoffset; 1871 offsets[idx].y = voffset; 1872 DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx); 1873 return 0; 1874 } 1875 1876 static bool drm_target_preferred(struct drm_fb_helper *fb_helper, 1877 struct drm_display_mode **modes, 1878 struct drm_fb_offset *offsets, 1879 bool *enabled, int width, int height) 1880 { 1881 struct drm_fb_helper_connector *fb_helper_conn; 1882 int i; 1883 uint64_t conn_configured = 0, mask; 1884 int tile_pass = 0; 1885 mask = (1 << fb_helper->connector_count) - 1; 1886 retry: 1887 for (i = 0; i < fb_helper->connector_count; i++) { 1888 fb_helper_conn = fb_helper->connector_info[i]; 1889 1890 if (conn_configured & (1 << i)) 1891 continue; 1892 1893 if (enabled[i] == false) { 1894 conn_configured |= (1 << i); 1895 continue; 1896 } 1897 1898 /* first pass over all the untiled connectors */ 1899 if (tile_pass == 0 && fb_helper_conn->connector->has_tile) 1900 continue; 1901 1902 if (tile_pass == 1) { 1903 if (fb_helper_conn->connector->tile_h_loc != 0 || 1904 fb_helper_conn->connector->tile_v_loc != 0) 1905 continue; 1906 1907 } else { 1908 if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && 1909 fb_helper_conn->connector->tile_v_loc != tile_pass - 1) 1910 /* if this tile_pass doesn't cover any of the tiles - keep going */ 1911 continue; 1912 1913 /* find the tile offsets for this pass - need 1914 to find all tiles left and above */ 1915 drm_get_tile_offsets(fb_helper, modes, offsets, 1916 i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); 1917 } 1918 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", 1919 fb_helper_conn->connector->base.id); 1920 1921 /* got for command line mode first */ 1922 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); 1923 if (!modes[i]) { 1924 DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", 1925 fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0); 1926 modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); 1927 } 1928 /* No preferred modes, pick one off the list */ 1929 if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) { 1930 list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head) 1931 break; 1932 } 1933 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : 1934 "none"); 1935 conn_configured |= (1 << i); 1936 } 1937 1938 if ((conn_configured & mask) != mask) { 1939 tile_pass++; 1940 goto retry; 1941 } 1942 return true; 1943 } 1944 1945 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, 1946 struct drm_fb_helper_crtc **best_crtcs, 1947 struct drm_display_mode **modes, 1948 int n, int width, int height) 1949 { 1950 int c, o; 1951 struct drm_device *dev = fb_helper->dev; 1952 struct drm_connector *connector; 1953 const struct drm_connector_helper_funcs *connector_funcs; 1954 struct drm_encoder *encoder; 1955 int my_score, best_score, score; 1956 struct drm_fb_helper_crtc **crtcs, *crtc; 1957 struct drm_fb_helper_connector *fb_helper_conn; 1958 1959 if (n == fb_helper->connector_count) 1960 return 0; 1961 1962 fb_helper_conn = fb_helper->connector_info[n]; 1963 connector = fb_helper_conn->connector; 1964 1965 best_crtcs[n] = NULL; 1966 best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); 1967 if (modes[n] == NULL) 1968 return best_score; 1969 1970 crtcs = kzalloc(dev->mode_config.num_connector * 1971 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); 1972 if (!crtcs) 1973 return best_score; 1974 1975 my_score = 1; 1976 if (connector->status == connector_status_connected) 1977 my_score++; 1978 if (drm_has_cmdline_mode(fb_helper_conn)) 1979 my_score++; 1980 if (drm_has_preferred_mode(fb_helper_conn, width, height)) 1981 my_score++; 1982 1983 connector_funcs = connector->helper_private; 1984 encoder = connector_funcs->best_encoder(connector); 1985 if (!encoder) 1986 goto out; 1987 1988 /* select a crtc for this connector and then attempt to configure 1989 remaining connectors */ 1990 for (c = 0; c < fb_helper->crtc_count; c++) { 1991 crtc = &fb_helper->crtc_info[c]; 1992 1993 if ((encoder->possible_crtcs & (1 << c)) == 0) 1994 continue; 1995 1996 for (o = 0; o < n; o++) 1997 if (best_crtcs[o] == crtc) 1998 break; 1999 2000 if (o < n) { 2001 /* ignore cloning unless only a single crtc */ 2002 if (fb_helper->crtc_count > 1) 2003 continue; 2004 2005 if (!drm_mode_equal(modes[o], modes[n])) 2006 continue; 2007 } 2008 2009 crtcs[n] = crtc; 2010 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); 2011 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, 2012 width, height); 2013 if (score > best_score) { 2014 best_score = score; 2015 memcpy(best_crtcs, crtcs, 2016 dev->mode_config.num_connector * 2017 sizeof(struct drm_fb_helper_crtc *)); 2018 } 2019 } 2020 out: 2021 kfree(crtcs); 2022 return best_score; 2023 } 2024 2025 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) 2026 { 2027 struct drm_device *dev = fb_helper->dev; 2028 struct drm_fb_helper_crtc **crtcs; 2029 struct drm_display_mode **modes; 2030 struct drm_fb_offset *offsets; 2031 struct drm_mode_set *modeset; 2032 bool *enabled; 2033 int width, height; 2034 int i; 2035 2036 DRM_DEBUG_KMS("\n"); 2037 2038 width = dev->mode_config.max_width; 2039 height = dev->mode_config.max_height; 2040 2041 crtcs = kcalloc(dev->mode_config.num_connector, 2042 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); 2043 modes = kcalloc(dev->mode_config.num_connector, 2044 sizeof(struct drm_display_mode *), GFP_KERNEL); 2045 offsets = kcalloc(dev->mode_config.num_connector, 2046 sizeof(struct drm_fb_offset), GFP_KERNEL); 2047 enabled = kcalloc(dev->mode_config.num_connector, 2048 sizeof(bool), GFP_KERNEL); 2049 if (!crtcs || !modes || !enabled || !offsets) { 2050 DRM_ERROR("Memory allocation failed\n"); 2051 goto out; 2052 } 2053 2054 2055 drm_enable_connectors(fb_helper, enabled); 2056 2057 if (!(fb_helper->funcs->initial_config && 2058 fb_helper->funcs->initial_config(fb_helper, crtcs, modes, 2059 offsets, 2060 enabled, width, height))) { 2061 memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); 2062 memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); 2063 memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0])); 2064 2065 if (!drm_target_cloned(fb_helper, modes, offsets, 2066 enabled, width, height) && 2067 !drm_target_preferred(fb_helper, modes, offsets, 2068 enabled, width, height)) 2069 DRM_ERROR("Unable to find initial modes\n"); 2070 2071 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", 2072 width, height); 2073 2074 drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); 2075 } 2076 2077 /* need to set the modesets up here for use later */ 2078 /* fill out the connector<->crtc mappings into the modesets */ 2079 for (i = 0; i < fb_helper->crtc_count; i++) { 2080 modeset = &fb_helper->crtc_info[i].mode_set; 2081 modeset->num_connectors = 0; 2082 modeset->fb = NULL; 2083 } 2084 2085 for (i = 0; i < fb_helper->connector_count; i++) { 2086 struct drm_display_mode *mode = modes[i]; 2087 struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; 2088 struct drm_fb_offset *offset = &offsets[i]; 2089 modeset = &fb_crtc->mode_set; 2090 2091 if (mode && fb_crtc) { 2092 DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", 2093 mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); 2094 fb_crtc->desired_mode = mode; 2095 fb_crtc->x = offset->x; 2096 fb_crtc->y = offset->y; 2097 if (modeset->mode) 2098 drm_mode_destroy(dev, modeset->mode); 2099 modeset->mode = drm_mode_duplicate(dev, 2100 fb_crtc->desired_mode); 2101 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; 2102 modeset->fb = fb_helper->fb; 2103 modeset->x = offset->x; 2104 modeset->y = offset->y; 2105 } 2106 } 2107 2108 /* Clear out any old modes if there are no more connected outputs. */ 2109 for (i = 0; i < fb_helper->crtc_count; i++) { 2110 modeset = &fb_helper->crtc_info[i].mode_set; 2111 if (modeset->num_connectors == 0) { 2112 BUG_ON(modeset->fb); 2113 if (modeset->mode) 2114 drm_mode_destroy(dev, modeset->mode); 2115 modeset->mode = NULL; 2116 } 2117 } 2118 out: 2119 kfree(crtcs); 2120 kfree(modes); 2121 kfree(offsets); 2122 kfree(enabled); 2123 } 2124 2125 /** 2126 * drm_fb_helper_initial_config - setup a sane initial connector configuration 2127 * @fb_helper: fb_helper device struct 2128 * @bpp_sel: bpp value to use for the framebuffer configuration 2129 * 2130 * Scans the CRTCs and connectors and tries to put together an initial setup. 2131 * At the moment, this is a cloned configuration across all heads with 2132 * a new framebuffer object as the backing store. 2133 * 2134 * Note that this also registers the fbdev and so allows userspace to call into 2135 * the driver through the fbdev interfaces. 2136 * 2137 * This function will call down into the ->fb_probe callback to let 2138 * the driver allocate and initialize the fbdev info structure and the drm 2139 * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and 2140 * drm_fb_helper_fill_fix() are provided as helpers to setup simple default 2141 * values for the fbdev info structure. 2142 * 2143 * RETURNS: 2144 * Zero if everything went ok, nonzero otherwise. 2145 */ 2146 int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) 2147 { 2148 struct drm_device *dev = fb_helper->dev; 2149 int count = 0; 2150 2151 if (!drm_fbdev_emulation) 2152 return 0; 2153 2154 mutex_lock(&dev->mode_config.mutex); 2155 count = drm_fb_helper_probe_connector_modes(fb_helper, 2156 dev->mode_config.max_width, 2157 dev->mode_config.max_height); 2158 mutex_unlock(&dev->mode_config.mutex); 2159 /* 2160 * we shouldn't end up with no modes here. 2161 */ 2162 if (count == 0) 2163 dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n"); 2164 2165 drm_setup_crtcs(fb_helper); 2166 2167 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); 2168 } 2169 EXPORT_SYMBOL(drm_fb_helper_initial_config); 2170 2171 /** 2172 * drm_fb_helper_hotplug_event - respond to a hotplug notification by 2173 * probing all the outputs attached to the fb 2174 * @fb_helper: the drm_fb_helper 2175 * 2176 * Scan the connectors attached to the fb_helper and try to put together a 2177 * setup after *notification of a change in output configuration. 2178 * 2179 * Called at runtime, takes the mode config locks to be able to check/change the 2180 * modeset configuration. Must be run from process context (which usually means 2181 * either the output polling work or a work item launched from the driver's 2182 * hotplug interrupt). 2183 * 2184 * Note that drivers may call this even before calling 2185 * drm_fb_helper_initial_config but only aftert drm_fb_helper_init. This allows 2186 * for a race-free fbcon setup and will make sure that the fbdev emulation will 2187 * not miss any hotplug events. 2188 * 2189 * RETURNS: 2190 * 0 on success and a non-zero error code otherwise. 2191 */ 2192 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) 2193 { 2194 struct drm_device *dev = fb_helper->dev; 2195 u32 max_width, max_height; 2196 2197 if (!drm_fbdev_emulation) 2198 return 0; 2199 2200 mutex_lock(&fb_helper->dev->mode_config.mutex); 2201 if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) { 2202 fb_helper->delayed_hotplug = true; 2203 mutex_unlock(&fb_helper->dev->mode_config.mutex); 2204 return 0; 2205 } 2206 DRM_DEBUG_KMS("\n"); 2207 2208 max_width = fb_helper->fb->width; 2209 max_height = fb_helper->fb->height; 2210 2211 drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); 2212 mutex_unlock(&fb_helper->dev->mode_config.mutex); 2213 2214 drm_modeset_lock_all(dev); 2215 drm_setup_crtcs(fb_helper); 2216 drm_modeset_unlock_all(dev); 2217 drm_fb_helper_set_par(fb_helper->fbdev); 2218 2219 return 0; 2220 } 2221 EXPORT_SYMBOL(drm_fb_helper_hotplug_event); 2222 2223 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT) 2224 * but the module doesn't depend on any fb console symbols. At least 2225 * attempt to load fbcon to avoid leaving the system without a usable console. 2226 */ 2227 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT) 2228 static int __init drm_fb_helper_modinit(void) 2229 { 2230 const char *name = "fbcon"; 2231 struct module *fbcon; 2232 2233 mutex_lock(&module_mutex); 2234 fbcon = find_module(name); 2235 mutex_unlock(&module_mutex); 2236 2237 if (!fbcon) 2238 request_module_nowait(name); 2239 return 0; 2240 } 2241 2242 module_init(drm_fb_helper_modinit); 2243 #endif 2244