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