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