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 <linux/device.h> 38 #include <linux/export.h> 39 #include <linux/list.h> 40 #include <linux/notifier.h> 41 #include <linux/printk.h> 42 #include <linux/sysrq.h> 43 #include <asm/bug.h> 44 #include <drm/drmP.h> 45 #include <drm/drm_crtc.h> 46 #include <drm/drm_fb_helper.h> 47 #include <drm/drm_crtc_helper.h> 48 49 #ifdef __NetBSD__ /* XXX LIST_HEAD means something else */ 50 static struct list_head kernel_fb_helper_list = 51 LIST_HEAD_INIT(kernel_fb_helper_list); 52 #else 53 static LIST_HEAD(kernel_fb_helper_list); 54 #endif 55 56 /** 57 * DOC: fbdev helpers 58 * 59 * The fb helper functions are useful to provide an fbdev on top of a drm kernel 60 * mode setting driver. They can be used mostly independantely from the crtc 61 * helper functions used by many drivers to implement the kernel mode setting 62 * interfaces. 63 * 64 * Initialization is done as a three-step process with drm_fb_helper_init(), 65 * drm_fb_helper_single_add_all_connectors() and drm_fb_helper_initial_config(). 66 * Drivers with fancier requirements than the default beheviour can override the 67 * second step with their own code. Teardown is done with drm_fb_helper_fini(). 68 * 69 * At runtime drivers should restore the fbdev console by calling 70 * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They 71 * should also notify the fb helper code from updates to the output 72 * configuration by calling drm_fb_helper_hotplug_event(). For easier 73 * integration with the output polling code in drm_crtc_helper.c the modeset 74 * code proves a ->output_poll_changed callback. 75 * 76 * All other functions exported by the fb helper library can be used to 77 * implement the fbdev driver interface by the driver. 78 */ 79 80 /** 81 * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev 82 * emulation helper 83 * @fb_helper: fbdev initialized with drm_fb_helper_init 84 * 85 * This functions adds all the available connectors for use with the given 86 * fb_helper. This is a separate step to allow drivers to freely assign 87 * connectors to the fbdev, e.g. if some are reserved for special purposes or 88 * not adequate to be used for the fbcon. 89 * 90 * Since this is part of the initial setup before the fbdev is published, no 91 * locking is required. 92 */ 93 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) 94 { 95 struct drm_device *dev = fb_helper->dev; 96 struct drm_connector *connector; 97 int i; 98 99 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 100 struct drm_fb_helper_connector *fb_helper_connector; 101 102 fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); 103 if (!fb_helper_connector) 104 goto fail; 105 106 fb_helper_connector->connector = connector; 107 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; 108 } 109 return 0; 110 fail: 111 for (i = 0; i < fb_helper->connector_count; i++) { 112 kfree(fb_helper->connector_info[i]); 113 fb_helper->connector_info[i] = NULL; 114 } 115 fb_helper->connector_count = 0; 116 return -ENOMEM; 117 } 118 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); 119 120 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) 121 { 122 struct drm_fb_helper_connector *fb_helper_conn; 123 int i; 124 125 for (i = 0; i < fb_helper->connector_count; i++) { 126 struct drm_cmdline_mode *mode; 127 struct drm_connector *connector; 128 char *option = NULL; 129 130 fb_helper_conn = fb_helper->connector_info[i]; 131 connector = fb_helper_conn->connector; 132 mode = &fb_helper_conn->cmdline_mode; 133 134 /* do something on return - turn off connector maybe */ 135 #if defined(__NetBSD__) 136 prop_dictionary_t prop = device_properties(connector->dev->dev); 137 if (prop_dictionary_get_cstring(prop, drm_get_connector_name(connector), &option) == false) 138 continue; 139 #else 140 if (fb_get_options(drm_get_connector_name(connector), &option)) 141 continue; 142 #endif 143 144 if (drm_mode_parse_command_line_for_connector(option, 145 connector, 146 mode)) { 147 if (mode->force) { 148 const char *s; 149 switch (mode->force) { 150 case DRM_FORCE_OFF: 151 s = "OFF"; 152 break; 153 case DRM_FORCE_ON_DIGITAL: 154 s = "ON - dig"; 155 break; 156 default: 157 case DRM_FORCE_ON: 158 s = "ON"; 159 break; 160 } 161 162 DRM_INFO("forcing %s connector %s\n", 163 drm_get_connector_name(connector), s); 164 connector->force = mode->force; 165 } 166 167 DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", 168 drm_get_connector_name(connector), 169 mode->xres, mode->yres, 170 mode->refresh_specified ? mode->refresh : 60, 171 mode->rb ? " reduced blanking" : "", 172 mode->margins ? " with margins" : "", 173 mode->interlace ? " interlaced" : ""); 174 } 175 176 } 177 return 0; 178 } 179 180 static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) 181 { 182 uint16_t *r_base, *g_base, *b_base; 183 int i; 184 185 if (helper->funcs->gamma_get == NULL) 186 return; 187 188 r_base = crtc->gamma_store; 189 g_base = r_base + crtc->gamma_size; 190 b_base = g_base + crtc->gamma_size; 191 192 for (i = 0; i < crtc->gamma_size; i++) 193 helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i); 194 } 195 196 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) 197 { 198 uint16_t *r_base, *g_base, *b_base; 199 200 if (crtc->funcs->gamma_set == NULL) 201 return; 202 203 r_base = crtc->gamma_store; 204 g_base = r_base + crtc->gamma_size; 205 b_base = g_base + crtc->gamma_size; 206 207 crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); 208 } 209 210 /** 211 * drm_fb_helper_debug_enter - implementation for ->fb_debug_enter 212 * @info: fbdev registered by the helper 213 */ 214 #ifndef __NetBSD__ 215 int drm_fb_helper_debug_enter(struct fb_info *info) 216 { 217 return drm_fb_helper_debug_enter_fb(info->par); 218 } 219 #endif 220 221 int 222 drm_fb_helper_debug_enter_fb(struct drm_fb_helper *helper) 223 { 224 struct drm_crtc_helper_funcs *funcs; 225 int i; 226 227 if (list_empty(&kernel_fb_helper_list)) 228 return false; 229 230 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { 231 for (i = 0; i < helper->crtc_count; i++) { 232 struct drm_mode_set *mode_set = 233 &helper->crtc_info[i].mode_set; 234 235 if (!mode_set->crtc->enabled) 236 continue; 237 238 funcs = mode_set->crtc->helper_private; 239 drm_fb_helper_save_lut_atomic(mode_set->crtc, helper); 240 funcs->mode_set_base_atomic(mode_set->crtc, 241 mode_set->fb, 242 mode_set->x, 243 mode_set->y, 244 ENTER_ATOMIC_MODE_SET); 245 } 246 } 247 248 return 0; 249 } 250 EXPORT_SYMBOL(drm_fb_helper_debug_enter); 251 252 /* Find the real fb for a given fb helper CRTC */ 253 static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) 254 { 255 struct drm_device *dev = crtc->dev; 256 struct drm_crtc *c; 257 258 list_for_each_entry(c, &dev->mode_config.crtc_list, head) { 259 if (crtc->base.id == c->base.id) 260 return c->primary->fb; 261 } 262 263 return NULL; 264 } 265 266 /** 267 * drm_fb_helper_debug_leave - implementation for ->fb_debug_leave 268 * @info: fbdev registered by the helper 269 */ 270 #ifndef __NetBSD__ 271 int drm_fb_helper_debug_leave(struct fb_info *info) 272 { 273 return drm_fb_helper_debug_leave_fb(info->par); 274 } 275 #endif 276 277 int 278 drm_fb_helper_debug_leave_fb(struct drm_fb_helper *helper) 279 { 280 struct drm_crtc *crtc; 281 struct drm_crtc_helper_funcs *funcs; 282 struct drm_framebuffer *fb; 283 int i; 284 285 for (i = 0; i < helper->crtc_count; i++) { 286 struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; 287 crtc = mode_set->crtc; 288 funcs = crtc->helper_private; 289 fb = drm_mode_config_fb(crtc); 290 291 if (!crtc->enabled) 292 continue; 293 294 if (!fb) { 295 DRM_ERROR("no fb to restore??\n"); 296 continue; 297 } 298 299 drm_fb_helper_restore_lut_atomic(mode_set->crtc); 300 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, 301 crtc->y, LEAVE_ATOMIC_MODE_SET); 302 } 303 304 return 0; 305 } 306 EXPORT_SYMBOL(drm_fb_helper_debug_leave); 307 308 /** 309 * drm_fb_helper_restore_fbdev_mode - restore fbdev configuration 310 * @fb_helper: fbcon to restore 311 * 312 * This should be called from driver's drm ->lastclose callback 313 * when implementing an fbcon on top of kms using this helper. This ensures that 314 * the user isn't greeted with a black screen when e.g. X dies. 315 */ 316 bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) 317 { 318 struct drm_device *dev = fb_helper->dev; 319 struct drm_plane *plane; 320 bool error = false; 321 int i; 322 323 drm_warn_on_modeset_not_all_locked(dev); 324 325 list_for_each_entry(plane, &dev->mode_config.plane_list, head) 326 if (plane->type != DRM_PLANE_TYPE_PRIMARY) 327 drm_plane_force_disable(plane); 328 329 for (i = 0; i < fb_helper->crtc_count; i++) { 330 struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 331 struct drm_crtc *crtc = mode_set->crtc; 332 int ret; 333 334 if (crtc->funcs->cursor_set) { 335 ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0); 336 if (ret) 337 error = true; 338 } 339 340 ret = drm_mode_set_config_internal(mode_set); 341 if (ret) 342 error = true; 343 } 344 return error; 345 } 346 EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); 347 348 /* 349 * restore fbcon display for all kms driver's using this helper, used for sysrq 350 * and panic handling. 351 */ 352 static bool drm_fb_helper_force_kernel_mode(void) 353 { 354 bool ret, error = false; 355 struct drm_fb_helper *helper; 356 357 if (list_empty(&kernel_fb_helper_list)) 358 return false; 359 360 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { 361 if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF) 362 continue; 363 364 ret = drm_fb_helper_restore_fbdev_mode(helper); 365 if (ret) 366 error = true; 367 } 368 return error; 369 } 370 371 static int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, 372 void *panic_str) 373 { 374 /* 375 * It's a waste of time and effort to switch back to text console 376 * if the kernel should reboot before panic messages can be seen. 377 */ 378 if (panic_timeout < 0) 379 return 0; 380 381 pr_err("panic occurred, switching back to text console\n"); 382 return drm_fb_helper_force_kernel_mode(); 383 } 384 385 static struct notifier_block paniced = { 386 .notifier_call = drm_fb_helper_panic, 387 }; 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 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 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 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) 415 { 416 bool ret; 417 ret = drm_fb_helper_force_kernel_mode(); 418 if (ret == true) 419 DRM_ERROR("Failed to restore crtc configuration\n"); 420 } 421 static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn); 422 423 static void drm_fb_helper_sysrq(int dummy1) 424 { 425 schedule_work(&drm_fb_helper_restore_work); 426 } 427 428 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { 429 .handler = drm_fb_helper_sysrq, 430 .help_msg = "force-fb(V)", 431 .action_msg = "Restore framebuffer console", 432 }; 433 #else 434 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op; 435 #endif 436 437 #ifndef __NetBSD__ /* XXX fb info */ 438 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) 439 { 440 struct drm_fb_helper *fb_helper = info->par; 441 struct drm_device *dev = fb_helper->dev; 442 struct drm_crtc *crtc; 443 struct drm_connector *connector; 444 int i, j; 445 446 /* 447 * fbdev->blank can be called from irq context in case of a panic. 448 * Since we already have our own special panic handler which will 449 * restore the fbdev console mode completely, just bail out early. 450 */ 451 if (oops_in_progress) 452 return; 453 454 /* 455 * For each CRTC in this fb, turn the connectors on/off. 456 */ 457 drm_modeset_lock_all(dev); 458 if (!drm_fb_helper_is_bound(fb_helper)) { 459 drm_modeset_unlock_all(dev); 460 return; 461 } 462 463 for (i = 0; i < fb_helper->crtc_count; i++) { 464 crtc = fb_helper->crtc_info[i].mode_set.crtc; 465 466 if (!crtc->enabled) 467 continue; 468 469 /* Walk the connectors & encoders on this fb turning them on/off */ 470 for (j = 0; j < fb_helper->connector_count; j++) { 471 connector = fb_helper->connector_info[j]->connector; 472 connector->funcs->dpms(connector, dpms_mode); 473 drm_object_property_set_value(&connector->base, 474 dev->mode_config.dpms_property, dpms_mode); 475 } 476 } 477 drm_modeset_unlock_all(dev); 478 } 479 480 /** 481 * drm_fb_helper_blank - implementation for ->fb_blank 482 * @blank: desired blanking state 483 * @info: fbdev registered by the helper 484 */ 485 int drm_fb_helper_blank(int blank, struct fb_info *info) 486 { 487 switch (blank) { 488 /* Display: On; HSync: On, VSync: On */ 489 case FB_BLANK_UNBLANK: 490 drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON); 491 break; 492 /* Display: Off; HSync: On, VSync: On */ 493 case FB_BLANK_NORMAL: 494 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY); 495 break; 496 /* Display: Off; HSync: Off, VSync: On */ 497 case FB_BLANK_HSYNC_SUSPEND: 498 drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY); 499 break; 500 /* Display: Off; HSync: On, VSync: Off */ 501 case FB_BLANK_VSYNC_SUSPEND: 502 drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND); 503 break; 504 /* Display: Off; HSync: Off, VSync: Off */ 505 case FB_BLANK_POWERDOWN: 506 drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF); 507 break; 508 } 509 return 0; 510 } 511 EXPORT_SYMBOL(drm_fb_helper_blank); 512 #endif 513 514 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) 515 { 516 int i; 517 518 for (i = 0; i < helper->connector_count; i++) 519 kfree(helper->connector_info[i]); 520 kfree(helper->connector_info); 521 for (i = 0; i < helper->crtc_count; i++) { 522 kfree(helper->crtc_info[i].mode_set.connectors); 523 if (helper->crtc_info[i].mode_set.mode) 524 drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode); 525 } 526 kfree(helper->crtc_info); 527 } 528 529 /** 530 * drm_fb_helper_init - initialize a drm_fb_helper structure 531 * @dev: drm device 532 * @fb_helper: driver-allocated fbdev helper structure to initialize 533 * @crtc_count: maximum number of crtcs to support in this fbdev emulation 534 * @max_conn_count: max connector count 535 * 536 * This allocates the structures for the fbdev helper with the given limits. 537 * Note that this won't yet touch the hardware (through the driver interfaces) 538 * nor register the fbdev. This is only done in drm_fb_helper_initial_config() 539 * to allow driver writes more control over the exact init sequence. 540 * 541 * Drivers must set fb_helper->funcs before calling 542 * drm_fb_helper_initial_config(). 543 * 544 * RETURNS: 545 * Zero if everything went ok, nonzero otherwise. 546 */ 547 int drm_fb_helper_init(struct drm_device *dev, 548 struct drm_fb_helper *fb_helper, 549 int crtc_count, int max_conn_count) 550 { 551 struct drm_crtc *crtc; 552 int i; 553 554 if (!max_conn_count) 555 return -EINVAL; 556 557 fb_helper->dev = dev; 558 559 INIT_LIST_HEAD(&fb_helper->kernel_fb_list); 560 561 fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); 562 if (!fb_helper->crtc_info) 563 return -ENOMEM; 564 565 fb_helper->crtc_count = crtc_count; 566 fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); 567 if (!fb_helper->connector_info) { 568 kfree(fb_helper->crtc_info); 569 return -ENOMEM; 570 } 571 fb_helper->connector_count = 0; 572 573 for (i = 0; i < crtc_count; i++) { 574 fb_helper->crtc_info[i].mode_set.connectors = 575 kcalloc(max_conn_count, 576 sizeof(struct drm_connector *), 577 GFP_KERNEL); 578 579 if (!fb_helper->crtc_info[i].mode_set.connectors) 580 goto out_free; 581 fb_helper->crtc_info[i].mode_set.num_connectors = 0; 582 } 583 584 i = 0; 585 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 586 fb_helper->crtc_info[i].mode_set.crtc = crtc; 587 i++; 588 } 589 590 return 0; 591 out_free: 592 drm_fb_helper_crtc_free(fb_helper); 593 return -ENOMEM; 594 } 595 EXPORT_SYMBOL(drm_fb_helper_init); 596 597 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) 598 { 599 if (!list_empty(&fb_helper->kernel_fb_list)) { 600 list_del(&fb_helper->kernel_fb_list); 601 if (list_empty(&kernel_fb_helper_list)) { 602 pr_info("drm: unregistered panic notifier\n"); 603 atomic_notifier_chain_unregister(&panic_notifier_list, 604 &paniced); 605 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 606 } 607 } 608 609 drm_fb_helper_crtc_free(fb_helper); 610 611 } 612 EXPORT_SYMBOL(drm_fb_helper_fini); 613 614 #ifndef __NetBSD__ /* XXX fb info */ 615 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, 616 u16 blue, u16 regno, struct fb_info *info) 617 { 618 struct drm_fb_helper *fb_helper = info->par; 619 struct drm_framebuffer *fb = fb_helper->fb; 620 int pindex; 621 622 if (info->fix.visual == FB_VISUAL_TRUECOLOR) { 623 u32 *palette; 624 u32 value; 625 /* place color in psuedopalette */ 626 if (regno > 16) 627 return -EINVAL; 628 palette = (u32 *)info->pseudo_palette; 629 red >>= (16 - info->var.red.length); 630 green >>= (16 - info->var.green.length); 631 blue >>= (16 - info->var.blue.length); 632 value = (red << info->var.red.offset) | 633 (green << info->var.green.offset) | 634 (blue << info->var.blue.offset); 635 if (info->var.transp.length > 0) { 636 u32 mask = (1 << info->var.transp.length) - 1; 637 mask <<= info->var.transp.offset; 638 value |= mask; 639 } 640 palette[regno] = value; 641 return 0; 642 } 643 644 /* 645 * The driver really shouldn't advertise pseudo/directcolor 646 * visuals if it can't deal with the palette. 647 */ 648 if (WARN_ON(!fb_helper->funcs->gamma_set || 649 !fb_helper->funcs->gamma_get)) 650 return -EINVAL; 651 652 pindex = regno; 653 654 if (fb->bits_per_pixel == 16) { 655 pindex = regno << 3; 656 657 if (fb->depth == 16 && regno > 63) 658 return -EINVAL; 659 if (fb->depth == 15 && regno > 31) 660 return -EINVAL; 661 662 if (fb->depth == 16) { 663 u16 r, g, b; 664 int i; 665 if (regno < 32) { 666 for (i = 0; i < 8; i++) 667 fb_helper->funcs->gamma_set(crtc, red, 668 green, blue, pindex + i); 669 } 670 671 fb_helper->funcs->gamma_get(crtc, &r, 672 &g, &b, 673 pindex >> 1); 674 675 for (i = 0; i < 4; i++) 676 fb_helper->funcs->gamma_set(crtc, r, 677 green, b, 678 (pindex >> 1) + i); 679 } 680 } 681 682 if (fb->depth != 16) 683 fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); 684 return 0; 685 } 686 687 /** 688 * drm_fb_helper_setcmap - implementation for ->fb_setcmap 689 * @cmap: cmap to set 690 * @info: fbdev registered by the helper 691 */ 692 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) 693 { 694 struct drm_fb_helper *fb_helper = info->par; 695 struct drm_device *dev = fb_helper->dev; 696 struct drm_crtc_helper_funcs *crtc_funcs; 697 u16 *red, *green, *blue, *transp; 698 struct drm_crtc *crtc; 699 int i, j, rc = 0; 700 int start; 701 702 drm_modeset_lock_all(dev); 703 if (!drm_fb_helper_is_bound(fb_helper)) { 704 drm_modeset_unlock_all(dev); 705 return -EBUSY; 706 } 707 708 for (i = 0; i < fb_helper->crtc_count; i++) { 709 crtc = fb_helper->crtc_info[i].mode_set.crtc; 710 crtc_funcs = crtc->helper_private; 711 712 red = cmap->red; 713 green = cmap->green; 714 blue = cmap->blue; 715 transp = cmap->transp; 716 start = cmap->start; 717 718 for (j = 0; j < cmap->len; j++) { 719 u16 hred, hgreen, hblue, htransp = 0xffff; 720 721 hred = *red++; 722 hgreen = *green++; 723 hblue = *blue++; 724 725 if (transp) 726 htransp = *transp++; 727 728 rc = setcolreg(crtc, hred, hgreen, hblue, start++, info); 729 if (rc) 730 goto out; 731 } 732 if (crtc_funcs->load_lut) 733 crtc_funcs->load_lut(crtc); 734 } 735 out: 736 drm_modeset_unlock_all(dev); 737 return rc; 738 } 739 EXPORT_SYMBOL(drm_fb_helper_setcmap); 740 741 /** 742 * drm_fb_helper_check_var - implementation for ->fb_check_var 743 * @var: screeninfo to check 744 * @info: fbdev registered by the helper 745 */ 746 int drm_fb_helper_check_var(struct fb_var_screeninfo *var, 747 struct fb_info *info) 748 { 749 struct drm_fb_helper *fb_helper = info->par; 750 struct drm_framebuffer *fb = fb_helper->fb; 751 int depth; 752 753 if (var->pixclock != 0 || in_dbg_master()) 754 return -EINVAL; 755 756 /* Need to resize the fb object !!! */ 757 if (var->bits_per_pixel > fb->bits_per_pixel || 758 var->xres > fb->width || var->yres > fb->height || 759 var->xres_virtual > fb->width || var->yres_virtual > fb->height) { 760 DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb " 761 "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n", 762 var->xres, var->yres, var->bits_per_pixel, 763 var->xres_virtual, var->yres_virtual, 764 fb->width, fb->height, fb->bits_per_pixel); 765 return -EINVAL; 766 } 767 768 switch (var->bits_per_pixel) { 769 case 16: 770 depth = (var->green.length == 6) ? 16 : 15; 771 break; 772 case 32: 773 depth = (var->transp.length > 0) ? 32 : 24; 774 break; 775 default: 776 depth = var->bits_per_pixel; 777 break; 778 } 779 780 switch (depth) { 781 case 8: 782 var->red.offset = 0; 783 var->green.offset = 0; 784 var->blue.offset = 0; 785 var->red.length = 8; 786 var->green.length = 8; 787 var->blue.length = 8; 788 var->transp.length = 0; 789 var->transp.offset = 0; 790 break; 791 case 15: 792 var->red.offset = 10; 793 var->green.offset = 5; 794 var->blue.offset = 0; 795 var->red.length = 5; 796 var->green.length = 5; 797 var->blue.length = 5; 798 var->transp.length = 1; 799 var->transp.offset = 15; 800 break; 801 case 16: 802 var->red.offset = 11; 803 var->green.offset = 5; 804 var->blue.offset = 0; 805 var->red.length = 5; 806 var->green.length = 6; 807 var->blue.length = 5; 808 var->transp.length = 0; 809 var->transp.offset = 0; 810 break; 811 case 24: 812 var->red.offset = 16; 813 var->green.offset = 8; 814 var->blue.offset = 0; 815 var->red.length = 8; 816 var->green.length = 8; 817 var->blue.length = 8; 818 var->transp.length = 0; 819 var->transp.offset = 0; 820 break; 821 case 32: 822 var->red.offset = 16; 823 var->green.offset = 8; 824 var->blue.offset = 0; 825 var->red.length = 8; 826 var->green.length = 8; 827 var->blue.length = 8; 828 var->transp.length = 8; 829 var->transp.offset = 24; 830 break; 831 default: 832 return -EINVAL; 833 } 834 return 0; 835 } 836 EXPORT_SYMBOL(drm_fb_helper_check_var); 837 #endif 838 839 #ifndef __NetBSD__ /* XXX fb info */ 840 /** 841 * drm_fb_helper_set_par - implementation for ->fb_set_par 842 * @info: fbdev registered by the helper 843 * 844 * This will let fbcon do the mode init and is called at initialization time by 845 * the fbdev core when registering the driver, and later on through the hotplug 846 * callback. 847 */ 848 int drm_fb_helper_set_par(struct fb_info *info) 849 { 850 struct drm_fb_helper *fb_helper = info->par; 851 struct fb_var_screeninfo *var = &info->var; 852 853 if (var->pixclock != 0) { 854 DRM_ERROR("PIXEL CLOCK SET\n"); 855 return -EINVAL; 856 } 857 858 return drm_fb_helper_set_config(fb_helper); 859 } 860 EXPORT_SYMBOL(drm_fb_helper_set_par); 861 #endif 862 863 int 864 drm_fb_helper_set_config(struct drm_fb_helper *fb_helper) 865 { 866 struct drm_device *dev = fb_helper->dev; 867 868 drm_modeset_lock_all(dev); 869 drm_fb_helper_restore_fbdev_mode(fb_helper); 870 drm_modeset_unlock_all(dev); 871 872 if (fb_helper->delayed_hotplug) { 873 fb_helper->delayed_hotplug = false; 874 drm_fb_helper_hotplug_event(fb_helper); 875 } 876 return 0; 877 } 878 879 #ifndef __NetBSD__ /* XXX fb info */ 880 /** 881 * drm_fb_helper_pan_display - implementation for ->fb_pan_display 882 * @var: updated screen information 883 * @info: fbdev registered by the helper 884 */ 885 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, 886 struct fb_info *info) 887 { 888 struct drm_fb_helper *fb_helper = info->par; 889 struct drm_device *dev = fb_helper->dev; 890 struct drm_mode_set *modeset; 891 int ret = 0; 892 int i; 893 894 drm_modeset_lock_all(dev); 895 if (!drm_fb_helper_is_bound(fb_helper)) { 896 drm_modeset_unlock_all(dev); 897 return -EBUSY; 898 } 899 900 for (i = 0; i < fb_helper->crtc_count; i++) { 901 modeset = &fb_helper->crtc_info[i].mode_set; 902 903 modeset->x = var->xoffset; 904 modeset->y = var->yoffset; 905 906 if (modeset->num_connectors) { 907 ret = drm_mode_set_config_internal(modeset); 908 if (!ret) { 909 info->var.xoffset = var->xoffset; 910 info->var.yoffset = var->yoffset; 911 } 912 } 913 } 914 drm_modeset_unlock_all(dev); 915 return ret; 916 } 917 EXPORT_SYMBOL(drm_fb_helper_pan_display); 918 #endif 919 920 /* 921 * Allocates the backing storage and sets up the fbdev info structure through 922 * the ->fb_probe callback and then registers the fbdev and sets up the panic 923 * notifier. 924 */ 925 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, 926 int preferred_bpp) 927 { 928 int ret = 0; 929 int crtc_count = 0; 930 int i; 931 #ifndef __NetBSD__ /* XXX fb info */ 932 struct fb_info *info; 933 #endif 934 struct drm_fb_helper_surface_size sizes; 935 int gamma_size = 0; 936 937 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); 938 sizes.surface_depth = 24; 939 sizes.surface_bpp = 32; 940 sizes.fb_width = (unsigned)-1; 941 sizes.fb_height = (unsigned)-1; 942 943 /* if driver picks 8 or 16 by default use that 944 for both depth/bpp */ 945 if (preferred_bpp != sizes.surface_bpp) 946 sizes.surface_depth = sizes.surface_bpp = preferred_bpp; 947 948 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 949 for (i = 0; i < fb_helper->connector_count; i++) { 950 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; 951 struct drm_cmdline_mode *cmdline_mode; 952 953 cmdline_mode = &fb_helper_conn->cmdline_mode; 954 955 if (cmdline_mode->bpp_specified) { 956 switch (cmdline_mode->bpp) { 957 case 8: 958 sizes.surface_depth = sizes.surface_bpp = 8; 959 break; 960 case 15: 961 sizes.surface_depth = 15; 962 sizes.surface_bpp = 16; 963 break; 964 case 16: 965 sizes.surface_depth = sizes.surface_bpp = 16; 966 break; 967 case 24: 968 sizes.surface_depth = sizes.surface_bpp = 24; 969 break; 970 case 32: 971 sizes.surface_depth = 24; 972 sizes.surface_bpp = 32; 973 break; 974 } 975 break; 976 } 977 } 978 979 crtc_count = 0; 980 for (i = 0; i < fb_helper->crtc_count; i++) { 981 struct drm_display_mode *desired_mode; 982 desired_mode = fb_helper->crtc_info[i].desired_mode; 983 984 if (desired_mode) { 985 if (gamma_size == 0) 986 gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; 987 if (desired_mode->hdisplay < sizes.fb_width) 988 sizes.fb_width = desired_mode->hdisplay; 989 if (desired_mode->vdisplay < sizes.fb_height) 990 sizes.fb_height = desired_mode->vdisplay; 991 if (desired_mode->hdisplay > sizes.surface_width) 992 sizes.surface_width = desired_mode->hdisplay; 993 if (desired_mode->vdisplay > sizes.surface_height) 994 sizes.surface_height = desired_mode->vdisplay; 995 crtc_count++; 996 } 997 } 998 999 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { 1000 /* hmm everyone went away - assume VGA cable just fell out 1001 and will come back later. */ 1002 DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); 1003 sizes.fb_width = sizes.surface_width = 1024; 1004 sizes.fb_height = sizes.surface_height = 768; 1005 } 1006 1007 /* push down into drivers */ 1008 ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); 1009 if (ret < 0) 1010 return ret; 1011 1012 #ifndef __NetBSD__ /* XXX fb info */ 1013 info = fb_helper->fbdev; 1014 #endif 1015 1016 /* 1017 * Set the fb pointer - usually drm_setup_crtcs does this for hotplug 1018 * events, but at init time drm_setup_crtcs needs to be called before 1019 * the fb is allocated (since we need to figure out the desired size of 1020 * the fb before we can allocate it ...). Hence we need to fix things up 1021 * here again. 1022 */ 1023 for (i = 0; i < fb_helper->crtc_count; i++) 1024 if (fb_helper->crtc_info[i].mode_set.num_connectors) 1025 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; 1026 1027 #ifndef __NetBSD__ /* XXX fb info */ 1028 info->var.pixclock = 0; 1029 if (register_framebuffer(info) < 0) 1030 return -EINVAL; 1031 1032 dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", 1033 info->node, info->fix.id); 1034 #endif 1035 1036 /* Switch back to kernel console on panic */ 1037 /* multi card linked list maybe */ 1038 if (list_empty(&kernel_fb_helper_list)) { 1039 dev_info(fb_helper->dev->dev, "registered panic notifier\n"); 1040 atomic_notifier_chain_register(&panic_notifier_list, 1041 &paniced); 1042 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 1043 } 1044 1045 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); 1046 1047 return 0; 1048 } 1049 1050 #ifndef __NetBSD__ /* XXX fb info */ 1051 /** 1052 * drm_fb_helper_fill_fix - initializes fixed fbdev information 1053 * @info: fbdev registered by the helper 1054 * @pitch: desired pitch 1055 * @depth: desired depth 1056 * 1057 * Helper to fill in the fixed fbdev information useful for a non-accelerated 1058 * fbdev emulations. Drivers which support acceleration methods which impose 1059 * additional constraints need to set up their own limits. 1060 * 1061 * Drivers should call this (or their equivalent setup code) from their 1062 * ->fb_probe callback. 1063 */ 1064 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 1065 uint32_t depth) 1066 { 1067 info->fix.type = FB_TYPE_PACKED_PIXELS; 1068 info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : 1069 FB_VISUAL_TRUECOLOR; 1070 info->fix.mmio_start = 0; 1071 info->fix.mmio_len = 0; 1072 info->fix.type_aux = 0; 1073 info->fix.xpanstep = 1; /* doing it in hw */ 1074 info->fix.ypanstep = 1; /* doing it in hw */ 1075 info->fix.ywrapstep = 0; 1076 info->fix.accel = FB_ACCEL_NONE; 1077 info->fix.type_aux = 0; 1078 1079 info->fix.line_length = pitch; 1080 return; 1081 } 1082 EXPORT_SYMBOL(drm_fb_helper_fill_fix); 1083 1084 /** 1085 * drm_fb_helper_fill_var - initalizes variable fbdev information 1086 * @info: fbdev instance to set up 1087 * @fb_helper: fb helper instance to use as template 1088 * @fb_width: desired fb width 1089 * @fb_height: desired fb height 1090 * 1091 * Sets up the variable fbdev metainformation from the given fb helper instance 1092 * and the drm framebuffer allocated in fb_helper->fb. 1093 * 1094 * Drivers should call this (or their equivalent setup code) from their 1095 * ->fb_probe callback after having allocated the fbdev backing 1096 * storage framebuffer. 1097 */ 1098 void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, 1099 uint32_t fb_width, uint32_t fb_height) 1100 { 1101 struct drm_framebuffer *fb = fb_helper->fb; 1102 info->pseudo_palette = fb_helper->pseudo_palette; 1103 info->var.xres_virtual = fb->width; 1104 info->var.yres_virtual = fb->height; 1105 info->var.bits_per_pixel = fb->bits_per_pixel; 1106 info->var.accel_flags = FB_ACCELF_TEXT; 1107 info->var.xoffset = 0; 1108 info->var.yoffset = 0; 1109 info->var.activate = FB_ACTIVATE_NOW; 1110 info->var.height = -1; 1111 info->var.width = -1; 1112 1113 switch (fb->depth) { 1114 case 8: 1115 info->var.red.offset = 0; 1116 info->var.green.offset = 0; 1117 info->var.blue.offset = 0; 1118 info->var.red.length = 8; /* 8bit DAC */ 1119 info->var.green.length = 8; 1120 info->var.blue.length = 8; 1121 info->var.transp.offset = 0; 1122 info->var.transp.length = 0; 1123 break; 1124 case 15: 1125 info->var.red.offset = 10; 1126 info->var.green.offset = 5; 1127 info->var.blue.offset = 0; 1128 info->var.red.length = 5; 1129 info->var.green.length = 5; 1130 info->var.blue.length = 5; 1131 info->var.transp.offset = 15; 1132 info->var.transp.length = 1; 1133 break; 1134 case 16: 1135 info->var.red.offset = 11; 1136 info->var.green.offset = 5; 1137 info->var.blue.offset = 0; 1138 info->var.red.length = 5; 1139 info->var.green.length = 6; 1140 info->var.blue.length = 5; 1141 info->var.transp.offset = 0; 1142 break; 1143 case 24: 1144 info->var.red.offset = 16; 1145 info->var.green.offset = 8; 1146 info->var.blue.offset = 0; 1147 info->var.red.length = 8; 1148 info->var.green.length = 8; 1149 info->var.blue.length = 8; 1150 info->var.transp.offset = 0; 1151 info->var.transp.length = 0; 1152 break; 1153 case 32: 1154 info->var.red.offset = 16; 1155 info->var.green.offset = 8; 1156 info->var.blue.offset = 0; 1157 info->var.red.length = 8; 1158 info->var.green.length = 8; 1159 info->var.blue.length = 8; 1160 info->var.transp.offset = 24; 1161 info->var.transp.length = 8; 1162 break; 1163 default: 1164 break; 1165 } 1166 1167 info->var.xres = fb_width; 1168 info->var.yres = fb_height; 1169 } 1170 EXPORT_SYMBOL(drm_fb_helper_fill_var); 1171 #endif 1172 1173 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, 1174 uint32_t maxX, 1175 uint32_t maxY) 1176 { 1177 struct drm_connector *connector; 1178 int count = 0; 1179 int i; 1180 1181 for (i = 0; i < fb_helper->connector_count; i++) { 1182 connector = fb_helper->connector_info[i]->connector; 1183 count += connector->funcs->fill_modes(connector, maxX, maxY); 1184 } 1185 1186 return count; 1187 } 1188 1189 struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height) 1190 { 1191 struct drm_display_mode *mode; 1192 1193 list_for_each_entry(mode, &fb_connector->connector->modes, head) { 1194 if (mode->hdisplay > width || 1195 mode->vdisplay > height) 1196 continue; 1197 if (mode->type & DRM_MODE_TYPE_PREFERRED) 1198 return mode; 1199 } 1200 return NULL; 1201 } 1202 EXPORT_SYMBOL(drm_has_preferred_mode); 1203 1204 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) 1205 { 1206 struct drm_cmdline_mode *cmdline_mode; 1207 cmdline_mode = &fb_connector->cmdline_mode; 1208 return cmdline_mode->specified; 1209 } 1210 1211 struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, 1212 int width, int height) 1213 { 1214 struct drm_cmdline_mode *cmdline_mode; 1215 struct drm_display_mode *mode = NULL; 1216 bool prefer_non_interlace; 1217 1218 cmdline_mode = &fb_helper_conn->cmdline_mode; 1219 if (cmdline_mode->specified == false) 1220 return mode; 1221 1222 /* attempt to find a matching mode in the list of modes 1223 * we have gotten so far, if not add a CVT mode that conforms 1224 */ 1225 if (cmdline_mode->rb || cmdline_mode->margins) 1226 goto create_mode; 1227 1228 prefer_non_interlace = !cmdline_mode->interlace; 1229 again: 1230 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { 1231 /* check width/height */ 1232 if (mode->hdisplay != cmdline_mode->xres || 1233 mode->vdisplay != cmdline_mode->yres) 1234 continue; 1235 1236 if (cmdline_mode->refresh_specified) { 1237 if (mode->vrefresh != cmdline_mode->refresh) 1238 continue; 1239 } 1240 1241 if (cmdline_mode->interlace) { 1242 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) 1243 continue; 1244 } else if (prefer_non_interlace) { 1245 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 1246 continue; 1247 } 1248 return mode; 1249 } 1250 1251 if (prefer_non_interlace) { 1252 prefer_non_interlace = false; 1253 goto again; 1254 } 1255 1256 create_mode: 1257 mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, 1258 cmdline_mode); 1259 list_add(&mode->head, &fb_helper_conn->connector->modes); 1260 return mode; 1261 } 1262 EXPORT_SYMBOL(drm_pick_cmdline_mode); 1263 1264 static bool drm_connector_enabled(struct drm_connector *connector, bool strict) 1265 { 1266 bool enable; 1267 1268 if (strict) 1269 enable = connector->status == connector_status_connected; 1270 else 1271 enable = connector->status != connector_status_disconnected; 1272 1273 return enable; 1274 } 1275 1276 static void drm_enable_connectors(struct drm_fb_helper *fb_helper, 1277 bool *enabled) 1278 { 1279 bool any_enabled = false; 1280 struct drm_connector *connector; 1281 int i = 0; 1282 1283 for (i = 0; i < fb_helper->connector_count; i++) { 1284 connector = fb_helper->connector_info[i]->connector; 1285 enabled[i] = drm_connector_enabled(connector, true); 1286 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id, 1287 enabled[i] ? "yes" : "no"); 1288 any_enabled |= enabled[i]; 1289 } 1290 1291 if (any_enabled) 1292 return; 1293 1294 for (i = 0; i < fb_helper->connector_count; i++) { 1295 connector = fb_helper->connector_info[i]->connector; 1296 enabled[i] = drm_connector_enabled(connector, false); 1297 } 1298 } 1299 1300 static bool drm_target_cloned(struct drm_fb_helper *fb_helper, 1301 struct drm_display_mode **modes, 1302 bool *enabled, int width, int height) 1303 { 1304 int count, i, j; 1305 bool can_clone = false; 1306 struct drm_fb_helper_connector *fb_helper_conn; 1307 struct drm_display_mode *dmt_mode, *mode; 1308 1309 /* only contemplate cloning in the single crtc case */ 1310 if (fb_helper->crtc_count > 1) 1311 return false; 1312 1313 count = 0; 1314 for (i = 0; i < fb_helper->connector_count; i++) { 1315 if (enabled[i]) 1316 count++; 1317 } 1318 1319 /* only contemplate cloning if more than one connector is enabled */ 1320 if (count <= 1) 1321 return false; 1322 1323 /* check the command line or if nothing common pick 1024x768 */ 1324 can_clone = true; 1325 for (i = 0; i < fb_helper->connector_count; i++) { 1326 if (!enabled[i]) 1327 continue; 1328 fb_helper_conn = fb_helper->connector_info[i]; 1329 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); 1330 if (!modes[i]) { 1331 can_clone = false; 1332 break; 1333 } 1334 for (j = 0; j < i; j++) { 1335 if (!enabled[j]) 1336 continue; 1337 if (!drm_mode_equal(modes[j], modes[i])) 1338 can_clone = false; 1339 } 1340 } 1341 1342 if (can_clone) { 1343 DRM_DEBUG_KMS("can clone using command line\n"); 1344 return true; 1345 } 1346 1347 /* try and find a 1024x768 mode on each connector */ 1348 can_clone = true; 1349 dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false); 1350 1351 for (i = 0; i < fb_helper->connector_count; i++) { 1352 1353 if (!enabled[i]) 1354 continue; 1355 1356 fb_helper_conn = fb_helper->connector_info[i]; 1357 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { 1358 if (drm_mode_equal(mode, dmt_mode)) 1359 modes[i] = mode; 1360 } 1361 if (!modes[i]) 1362 can_clone = false; 1363 } 1364 1365 if (can_clone) { 1366 DRM_DEBUG_KMS("can clone using 1024x768\n"); 1367 return true; 1368 } 1369 DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); 1370 return false; 1371 } 1372 1373 static bool drm_target_preferred(struct drm_fb_helper *fb_helper, 1374 struct drm_display_mode **modes, 1375 bool *enabled, int width, int height) 1376 { 1377 struct drm_fb_helper_connector *fb_helper_conn; 1378 int i; 1379 1380 for (i = 0; i < fb_helper->connector_count; i++) { 1381 fb_helper_conn = fb_helper->connector_info[i]; 1382 1383 if (enabled[i] == false) 1384 continue; 1385 1386 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", 1387 fb_helper_conn->connector->base.id); 1388 1389 /* got for command line mode first */ 1390 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); 1391 if (!modes[i]) { 1392 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", 1393 fb_helper_conn->connector->base.id); 1394 modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); 1395 } 1396 /* No preferred modes, pick one off the list */ 1397 if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) { 1398 list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head) 1399 break; 1400 } 1401 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : 1402 "none"); 1403 } 1404 return true; 1405 } 1406 1407 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, 1408 struct drm_fb_helper_crtc **best_crtcs, 1409 struct drm_display_mode **modes, 1410 int n, int width, int height) 1411 { 1412 int c, o; 1413 struct drm_device *dev = fb_helper->dev; 1414 struct drm_connector *connector; 1415 struct drm_connector_helper_funcs *connector_funcs; 1416 struct drm_encoder *encoder; 1417 int my_score, best_score, score; 1418 struct drm_fb_helper_crtc **crtcs, *crtc; 1419 struct drm_fb_helper_connector *fb_helper_conn; 1420 1421 if (n == fb_helper->connector_count) 1422 return 0; 1423 1424 fb_helper_conn = fb_helper->connector_info[n]; 1425 connector = fb_helper_conn->connector; 1426 1427 best_crtcs[n] = NULL; 1428 best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); 1429 if (modes[n] == NULL) 1430 return best_score; 1431 1432 crtcs = kzalloc(dev->mode_config.num_connector * 1433 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); 1434 if (!crtcs) 1435 return best_score; 1436 1437 my_score = 1; 1438 if (connector->status == connector_status_connected) 1439 my_score++; 1440 if (drm_has_cmdline_mode(fb_helper_conn)) 1441 my_score++; 1442 if (drm_has_preferred_mode(fb_helper_conn, width, height)) 1443 my_score++; 1444 1445 connector_funcs = connector->helper_private; 1446 encoder = connector_funcs->best_encoder(connector); 1447 if (!encoder) 1448 goto out; 1449 1450 /* select a crtc for this connector and then attempt to configure 1451 remaining connectors */ 1452 for (c = 0; c < fb_helper->crtc_count; c++) { 1453 crtc = &fb_helper->crtc_info[c]; 1454 1455 if ((encoder->possible_crtcs & (1 << c)) == 0) 1456 continue; 1457 1458 for (o = 0; o < n; o++) 1459 if (best_crtcs[o] == crtc) 1460 break; 1461 1462 if (o < n) { 1463 /* ignore cloning unless only a single crtc */ 1464 if (fb_helper->crtc_count > 1) 1465 continue; 1466 1467 if (!drm_mode_equal(modes[o], modes[n])) 1468 continue; 1469 } 1470 1471 crtcs[n] = crtc; 1472 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); 1473 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, 1474 width, height); 1475 if (score > best_score) { 1476 best_score = score; 1477 memcpy(best_crtcs, crtcs, 1478 dev->mode_config.num_connector * 1479 sizeof(struct drm_fb_helper_crtc *)); 1480 } 1481 } 1482 out: 1483 kfree(crtcs); 1484 return best_score; 1485 } 1486 1487 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) 1488 { 1489 struct drm_device *dev = fb_helper->dev; 1490 struct drm_fb_helper_crtc **crtcs; 1491 struct drm_display_mode **modes; 1492 struct drm_mode_set *modeset; 1493 bool *enabled; 1494 int width, height; 1495 int i; 1496 1497 DRM_DEBUG_KMS("\n"); 1498 1499 width = dev->mode_config.max_width; 1500 height = dev->mode_config.max_height; 1501 1502 crtcs = kcalloc(dev->mode_config.num_connector, 1503 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); 1504 modes = kcalloc(dev->mode_config.num_connector, 1505 sizeof(struct drm_display_mode *), GFP_KERNEL); 1506 enabled = kcalloc(dev->mode_config.num_connector, 1507 sizeof(bool), GFP_KERNEL); 1508 if (!crtcs || !modes || !enabled) { 1509 DRM_ERROR("Memory allocation failed\n"); 1510 goto out; 1511 } 1512 1513 1514 drm_enable_connectors(fb_helper, enabled); 1515 1516 if (!(fb_helper->funcs->initial_config && 1517 fb_helper->funcs->initial_config(fb_helper, crtcs, modes, 1518 enabled, width, height))) { 1519 memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); 1520 memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); 1521 1522 if (!drm_target_cloned(fb_helper, 1523 modes, enabled, width, height) && 1524 !drm_target_preferred(fb_helper, 1525 modes, enabled, width, height)) 1526 DRM_ERROR("Unable to find initial modes\n"); 1527 1528 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", 1529 width, height); 1530 1531 drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); 1532 } 1533 1534 /* need to set the modesets up here for use later */ 1535 /* fill out the connector<->crtc mappings into the modesets */ 1536 for (i = 0; i < fb_helper->crtc_count; i++) { 1537 modeset = &fb_helper->crtc_info[i].mode_set; 1538 modeset->num_connectors = 0; 1539 modeset->fb = NULL; 1540 } 1541 1542 for (i = 0; i < fb_helper->connector_count; i++) { 1543 struct drm_display_mode *mode = modes[i]; 1544 struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; 1545 modeset = &fb_crtc->mode_set; 1546 1547 if (mode && fb_crtc) { 1548 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", 1549 mode->name, fb_crtc->mode_set.crtc->base.id); 1550 fb_crtc->desired_mode = mode; 1551 if (modeset->mode) 1552 drm_mode_destroy(dev, modeset->mode); 1553 modeset->mode = drm_mode_duplicate(dev, 1554 fb_crtc->desired_mode); 1555 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; 1556 modeset->fb = fb_helper->fb; 1557 } 1558 } 1559 1560 /* Clear out any old modes if there are no more connected outputs. */ 1561 for (i = 0; i < fb_helper->crtc_count; i++) { 1562 modeset = &fb_helper->crtc_info[i].mode_set; 1563 if (modeset->num_connectors == 0) { 1564 BUG_ON(modeset->fb); 1565 BUG_ON(modeset->num_connectors); 1566 if (modeset->mode) 1567 drm_mode_destroy(dev, modeset->mode); 1568 modeset->mode = NULL; 1569 fb_helper->crtc_info[i].desired_mode = NULL; 1570 } 1571 } 1572 out: 1573 kfree(crtcs); 1574 kfree(modes); 1575 kfree(enabled); 1576 } 1577 1578 /** 1579 * drm_fb_helper_initial_config - setup a sane initial connector configuration 1580 * @fb_helper: fb_helper device struct 1581 * @bpp_sel: bpp value to use for the framebuffer configuration 1582 * 1583 * Scans the CRTCs and connectors and tries to put together an initial setup. 1584 * At the moment, this is a cloned configuration across all heads with 1585 * a new framebuffer object as the backing store. 1586 * 1587 * Note that this also registers the fbdev and so allows userspace to call into 1588 * the driver through the fbdev interfaces. 1589 * 1590 * This function will call down into the ->fb_probe callback to let 1591 * the driver allocate and initialize the fbdev info structure and the drm 1592 * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and 1593 * drm_fb_helper_fill_fix() are provided as helpers to setup simple default 1594 * values for the fbdev info structure. 1595 * 1596 * RETURNS: 1597 * Zero if everything went ok, nonzero otherwise. 1598 */ 1599 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) 1600 { 1601 struct drm_device *dev = fb_helper->dev; 1602 int count = 0; 1603 1604 drm_fb_helper_parse_command_line(fb_helper); 1605 1606 mutex_lock(&dev->mode_config.mutex); 1607 count = drm_fb_helper_probe_connector_modes(fb_helper, 1608 dev->mode_config.max_width, 1609 dev->mode_config.max_height); 1610 mutex_unlock(&dev->mode_config.mutex); 1611 /* 1612 * we shouldn't end up with no modes here. 1613 */ 1614 if (count == 0) 1615 dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n"); 1616 1617 drm_setup_crtcs(fb_helper); 1618 1619 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); 1620 } 1621 EXPORT_SYMBOL(drm_fb_helper_initial_config); 1622 1623 /** 1624 * drm_fb_helper_hotplug_event - respond to a hotplug notification by 1625 * probing all the outputs attached to the fb 1626 * @fb_helper: the drm_fb_helper 1627 * 1628 * Scan the connectors attached to the fb_helper and try to put together a 1629 * setup after *notification of a change in output configuration. 1630 * 1631 * Called at runtime, takes the mode config locks to be able to check/change the 1632 * modeset configuration. Must be run from process context (which usually means 1633 * either the output polling work or a work item launched from the driver's 1634 * hotplug interrupt). 1635 * 1636 * Note that the driver must ensure that this is only called _after_ the fb has 1637 * been fully set up, i.e. after the call to drm_fb_helper_initial_config. 1638 * 1639 * RETURNS: 1640 * 0 on success and a non-zero error code otherwise. 1641 */ 1642 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) 1643 { 1644 struct drm_device *dev = fb_helper->dev; 1645 u32 max_width, max_height; 1646 1647 if (!fb_helper->fb) 1648 return 0; 1649 1650 mutex_lock(&fb_helper->dev->mode_config.mutex); 1651 if (!drm_fb_helper_is_bound(fb_helper)) { 1652 fb_helper->delayed_hotplug = true; 1653 mutex_unlock(&fb_helper->dev->mode_config.mutex); 1654 return 0; 1655 } 1656 DRM_DEBUG_KMS("\n"); 1657 1658 max_width = fb_helper->fb->width; 1659 max_height = fb_helper->fb->height; 1660 1661 drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); 1662 mutex_unlock(&fb_helper->dev->mode_config.mutex); 1663 1664 drm_modeset_lock_all(dev); 1665 drm_setup_crtcs(fb_helper); 1666 drm_modeset_unlock_all(dev); 1667 #ifdef __NetBSD__ 1668 drm_fb_helper_set_config(fb_helper); 1669 #else 1670 drm_fb_helper_set_par(fb_helper->fbdev); 1671 #endif 1672 1673 return 0; 1674 } 1675 EXPORT_SYMBOL(drm_fb_helper_hotplug_event); 1676 1677 /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT) 1678 * but the module doesn't depend on any fb console symbols. At least 1679 * attempt to load fbcon to avoid leaving the system without a usable console. 1680 */ 1681 #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT) 1682 static int __init drm_fb_helper_modinit(void) 1683 { 1684 const char *name = "fbcon"; 1685 struct module *fbcon; 1686 1687 mutex_lock(&module_mutex); 1688 fbcon = find_module(name); 1689 mutex_unlock(&module_mutex); 1690 1691 if (!fbcon) 1692 request_module_nowait(name); 1693 return 0; 1694 } 1695 1696 module_init(drm_fb_helper_modinit); 1697 #endif 1698