Subversion Repositories Kolibri OS

Rev

Rev 6937 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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