Home | History | Annotate | Line # | Download | only in drm
      1  1.26  riastrad /*	$NetBSD: drm_fb_helper.c,v 1.26 2021/12/19 12:08:18 riastradh Exp $	*/
      2   1.9  riastrad 
      3   1.1  riastrad /*
      4   1.1  riastrad  * Copyright (c) 2006-2009 Red Hat Inc.
      5   1.1  riastrad  * Copyright (c) 2006-2008 Intel Corporation
      6   1.1  riastrad  * Copyright (c) 2007 Dave Airlie <airlied (at) linux.ie>
      7   1.1  riastrad  *
      8   1.1  riastrad  * DRM framebuffer helper functions
      9   1.1  riastrad  *
     10   1.1  riastrad  * Permission to use, copy, modify, distribute, and sell this software and its
     11   1.1  riastrad  * documentation for any purpose is hereby granted without fee, provided that
     12   1.1  riastrad  * the above copyright notice appear in all copies and that both that copyright
     13   1.1  riastrad  * notice and this permission notice appear in supporting documentation, and
     14   1.1  riastrad  * that the name of the copyright holders not be used in advertising or
     15   1.1  riastrad  * publicity pertaining to distribution of the software without specific,
     16   1.1  riastrad  * written prior permission.  The copyright holders make no representations
     17   1.1  riastrad  * about the suitability of this software for any purpose.  It is provided "as
     18   1.1  riastrad  * is" without express or implied warranty.
     19   1.1  riastrad  *
     20   1.1  riastrad  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     21   1.1  riastrad  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     22   1.1  riastrad  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     23   1.1  riastrad  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     24   1.1  riastrad  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     25   1.1  riastrad  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
     26   1.1  riastrad  * OF THIS SOFTWARE.
     27   1.1  riastrad  *
     28   1.1  riastrad  * Authors:
     29   1.1  riastrad  *      Dave Airlie <airlied (at) linux.ie>
     30   1.1  riastrad  *      Jesse Barnes <jesse.barnes (at) intel.com>
     31   1.1  riastrad  */
     32   1.9  riastrad #include <sys/cdefs.h>
     33  1.26  riastrad __KERNEL_RCSID(0, "$NetBSD: drm_fb_helper.c,v 1.26 2021/12/19 12:08:18 riastradh Exp $");
     34   1.9  riastrad 
     35   1.1  riastrad #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     36   1.1  riastrad 
     37  1.17  riastrad #include <linux/console.h>
     38  1.17  riastrad #include <linux/dma-buf.h>
     39   1.1  riastrad #include <linux/kernel.h>
     40  1.17  riastrad #include <linux/module.h>
     41   1.1  riastrad #include <linux/slab.h>
     42   1.2  riastrad #include <linux/sysrq.h>
     43  1.17  riastrad #include <linux/vmalloc.h>
     44  1.17  riastrad 
     45  1.17  riastrad #include <drm/drm_atomic.h>
     46   1.1  riastrad #include <drm/drm_crtc.h>
     47  1.17  riastrad #include <drm/drm_crtc_helper.h>
     48  1.17  riastrad #include <drm/drm_drv.h>
     49   1.1  riastrad #include <drm/drm_fb_helper.h>
     50  1.17  riastrad #include <drm/drm_fourcc.h>
     51  1.17  riastrad #include <drm/drm_print.h>
     52  1.17  riastrad #include <drm/drm_vblank.h>
     53  1.17  riastrad 
     54  1.17  riastrad #include "drm_crtc_helper_internal.h"
     55  1.17  riastrad #include "drm_internal.h"
     56   1.9  riastrad 
     57  1.24  riastrad #include <linux/nbsd-namespace.h>
     58  1.24  riastrad 
     59   1.9  riastrad static bool drm_fbdev_emulation = true;
     60   1.9  riastrad module_param_named(fbdev_emulation, drm_fbdev_emulation, bool, 0600);
     61   1.9  riastrad MODULE_PARM_DESC(fbdev_emulation,
     62   1.9  riastrad 		 "Enable legacy fbdev emulation [default=true]");
     63   1.1  riastrad 
     64  1.17  riastrad static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
     65  1.17  riastrad module_param(drm_fbdev_overalloc, int, 0444);
     66  1.17  riastrad MODULE_PARM_DESC(drm_fbdev_overalloc,
     67  1.17  riastrad 		 "Overallocation of the fbdev buffer (%) [default="
     68  1.17  riastrad 		 __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
     69  1.17  riastrad 
     70  1.17  riastrad /*
     71  1.17  riastrad  * In order to keep user-space compatibility, we want in certain use-cases
     72  1.17  riastrad  * to keep leaking the fbdev physical address to the user-space program
     73  1.17  riastrad  * handling the fbdev buffer.
     74  1.17  riastrad  * This is a bad habit essentially kept into closed source opengl driver
     75  1.17  riastrad  * that should really be moved into open-source upstream projects instead
     76  1.17  riastrad  * of using legacy physical addresses in user space to communicate with
     77  1.17  riastrad  * other out-of-tree kernel modules.
     78  1.17  riastrad  *
     79  1.17  riastrad  * This module_param *should* be removed as soon as possible and be
     80  1.17  riastrad  * considered as a broken and legacy behaviour from a modern fbdev device.
     81  1.17  riastrad  */
     82  1.17  riastrad #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
     83  1.17  riastrad static bool drm_leak_fbdev_smem = false;
     84  1.17  riastrad module_param_unsafe(drm_leak_fbdev_smem, bool, 0600);
     85  1.17  riastrad MODULE_PARM_DESC(drm_leak_fbdev_smem,
     86  1.17  riastrad 		 "Allow unsafe leaking fbdev physical smem address [default=false]");
     87  1.17  riastrad #endif
     88  1.17  riastrad 
     89   1.2  riastrad #ifdef __NetBSD__		/* XXX LIST_HEAD means something else */
     90   1.2  riastrad static struct list_head kernel_fb_helper_list =
     91   1.2  riastrad     LIST_HEAD_INIT(kernel_fb_helper_list);
     92  1.19  riastrad #define	kernel_fb_helper_lock	drm_kernel_fb_helper_lock
     93  1.19  riastrad struct mutex kernel_fb_helper_lock;
     94   1.2  riastrad #else
     95   1.1  riastrad static LIST_HEAD(kernel_fb_helper_list);
     96  1.19  riastrad static DEFINE_MUTEX(kernel_fb_helper_lock);
     97   1.2  riastrad #endif
     98   1.1  riastrad 
     99   1.1  riastrad /**
    100   1.1  riastrad  * DOC: fbdev helpers
    101   1.1  riastrad  *
    102   1.1  riastrad  * The fb helper functions are useful to provide an fbdev on top of a drm kernel
    103   1.9  riastrad  * mode setting driver. They can be used mostly independently from the crtc
    104   1.1  riastrad  * helper functions used by many drivers to implement the kernel mode setting
    105   1.1  riastrad  * interfaces.
    106   1.5  riastrad  *
    107  1.17  riastrad  * Drivers that support a dumb buffer with a virtual address and mmap support,
    108  1.17  riastrad  * should try out the generic fbdev emulation using drm_fbdev_generic_setup().
    109  1.17  riastrad  * It will automatically set up deferred I/O if the driver requires a shadow
    110  1.17  riastrad  * buffer.
    111   1.5  riastrad  *
    112  1.17  riastrad  * At runtime drivers should restore the fbdev console by using
    113  1.17  riastrad  * drm_fb_helper_lastclose() as their &drm_driver.lastclose callback.
    114   1.9  riastrad  * They should also notify the fb helper code from updates to the output
    115  1.17  riastrad  * configuration by using drm_fb_helper_output_poll_changed() as their
    116  1.17  riastrad  * &drm_mode_config_funcs.output_poll_changed callback.
    117  1.17  riastrad  *
    118  1.17  riastrad  * For suspend/resume consider using drm_mode_config_helper_suspend() and
    119  1.17  riastrad  * drm_mode_config_helper_resume() which takes care of fbdev as well.
    120   1.5  riastrad  *
    121   1.5  riastrad  * All other functions exported by the fb helper library can be used to
    122   1.5  riastrad  * implement the fbdev driver interface by the driver.
    123   1.9  riastrad  *
    124   1.9  riastrad  * It is possible, though perhaps somewhat tricky, to implement race-free
    125   1.9  riastrad  * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare()
    126   1.9  riastrad  * helper must be called first to initialize the minimum required to make
    127   1.9  riastrad  * hotplug detection work. Drivers also need to make sure to properly set up
    128  1.17  riastrad  * the &drm_mode_config.funcs member. After calling drm_kms_helper_poll_init()
    129   1.9  riastrad  * it is safe to enable interrupts and start processing hotplug events. At the
    130   1.9  riastrad  * same time, drivers should initialize all modeset objects such as CRTCs,
    131   1.9  riastrad  * encoders and connectors. To finish up the fbdev helper initialization, the
    132   1.9  riastrad  * drm_fb_helper_init() function is called. To probe for all attached displays
    133   1.9  riastrad  * and set up an initial configuration using the detected hardware, drivers
    134  1.17  riastrad  * should call drm_fb_helper_initial_config().
    135   1.5  riastrad  *
    136  1.17  riastrad  * If &drm_framebuffer_funcs.dirty is set, the
    137  1.17  riastrad  * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will
    138  1.17  riastrad  * accumulate changes and schedule &drm_fb_helper.dirty_work to run right
    139  1.17  riastrad  * away. This worker then calls the dirty() function ensuring that it will
    140  1.17  riastrad  * always run in process context since the fb_*() function could be running in
    141  1.17  riastrad  * atomic context. If drm_fb_helper_deferred_io() is used as the deferred_io
    142  1.17  riastrad  * callback it will also schedule dirty_work with the damage collected from the
    143  1.17  riastrad  * mmap page writes.
    144   1.5  riastrad  *
    145  1.17  riastrad  * Deferred I/O is not compatible with SHMEM. Such drivers should request an
    146  1.17  riastrad  * fbdev shadow buffer and call drm_fbdev_generic_setup() instead.
    147   1.5  riastrad  */
    148   1.1  riastrad 
    149   1.1  riastrad static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
    150   1.1  riastrad {
    151   1.1  riastrad 	uint16_t *r_base, *g_base, *b_base;
    152   1.1  riastrad 
    153   1.1  riastrad 	if (crtc->funcs->gamma_set == NULL)
    154   1.1  riastrad 		return;
    155   1.1  riastrad 
    156   1.1  riastrad 	r_base = crtc->gamma_store;
    157   1.1  riastrad 	g_base = r_base + crtc->gamma_size;
    158   1.1  riastrad 	b_base = g_base + crtc->gamma_size;
    159   1.1  riastrad 
    160  1.17  riastrad 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base,
    161  1.17  riastrad 			       crtc->gamma_size, NULL);
    162   1.1  riastrad }
    163   1.1  riastrad 
    164   1.5  riastrad /**
    165  1.17  riastrad  * drm_fb_helper_debug_enter - implementation for &fb_ops.fb_debug_enter
    166   1.5  riastrad  * @info: fbdev registered by the helper
    167   1.5  riastrad  */
    168  1.23  riastrad int drm_fb_helper_debug_enter_fb(struct drm_fb_helper *helper)
    169   1.1  riastrad {
    170   1.9  riastrad 	const struct drm_crtc_helper_funcs *funcs;
    171  1.17  riastrad 	struct drm_mode_set *mode_set;
    172   1.1  riastrad 
    173   1.1  riastrad 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
    174  1.25  riastrad 		drm_client_for_each_modeset_unlocked(mode_set, &helper->client) {
    175   1.1  riastrad 			if (!mode_set->crtc->enabled)
    176   1.1  riastrad 				continue;
    177   1.1  riastrad 
    178  1.26  riastrad 			if (drm_drv_uses_atomic_modeset(mode_set->crtc->dev))
    179  1.26  riastrad 				continue;
    180  1.26  riastrad 
    181   1.1  riastrad 			funcs =	mode_set->crtc->helper_private;
    182  1.17  riastrad 			if (funcs->mode_set_base_atomic == NULL)
    183  1.17  riastrad 				continue;
    184  1.17  riastrad 
    185   1.1  riastrad 			funcs->mode_set_base_atomic(mode_set->crtc,
    186   1.1  riastrad 						    mode_set->fb,
    187   1.1  riastrad 						    mode_set->x,
    188   1.1  riastrad 						    mode_set->y,
    189   1.1  riastrad 						    ENTER_ATOMIC_MODE_SET);
    190   1.1  riastrad 		}
    191   1.1  riastrad 	}
    192   1.1  riastrad 
    193   1.1  riastrad 	return 0;
    194   1.1  riastrad }
    195   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_debug_enter);
    196   1.1  riastrad 
    197   1.5  riastrad /**
    198  1.17  riastrad  * drm_fb_helper_debug_leave - implementation for &fb_ops.fb_debug_leave
    199   1.5  riastrad  * @info: fbdev registered by the helper
    200   1.5  riastrad  */
    201  1.23  riastrad int drm_fb_helper_debug_leave_fb(struct drm_fb_helper *helper)
    202   1.1  riastrad {
    203  1.17  riastrad 	struct drm_client_dev *client = &helper->client;
    204  1.17  riastrad 	struct drm_device *dev = helper->dev;
    205   1.1  riastrad 	struct drm_crtc *crtc;
    206   1.9  riastrad 	const struct drm_crtc_helper_funcs *funcs;
    207  1.17  riastrad 	struct drm_mode_set *mode_set;
    208   1.1  riastrad 	struct drm_framebuffer *fb;
    209   1.1  riastrad 
    210  1.25  riastrad 	drm_client_for_each_modeset_unlocked(mode_set, client) {
    211   1.1  riastrad 		crtc = mode_set->crtc;
    212  1.17  riastrad 		if (drm_drv_uses_atomic_modeset(crtc->dev))
    213  1.17  riastrad 			continue;
    214  1.17  riastrad 
    215   1.1  riastrad 		funcs = crtc->helper_private;
    216  1.17  riastrad 		fb = crtc->primary->fb;
    217   1.1  riastrad 
    218   1.1  riastrad 		if (!crtc->enabled)
    219   1.1  riastrad 			continue;
    220   1.1  riastrad 
    221   1.1  riastrad 		if (!fb) {
    222  1.17  riastrad 			drm_err(dev, "no fb to restore?\n");
    223   1.1  riastrad 			continue;
    224   1.1  riastrad 		}
    225   1.1  riastrad 
    226  1.17  riastrad 		if (funcs->mode_set_base_atomic == NULL)
    227  1.17  riastrad 			continue;
    228  1.17  riastrad 
    229   1.1  riastrad 		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
    230   1.1  riastrad 		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
    231   1.1  riastrad 					    crtc->y, LEAVE_ATOMIC_MODE_SET);
    232   1.1  riastrad 	}
    233   1.1  riastrad 
    234   1.1  riastrad 	return 0;
    235   1.1  riastrad }
    236   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_debug_leave);
    237   1.1  riastrad 
    238   1.9  riastrad /**
    239   1.9  riastrad  * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
    240  1.17  riastrad  * @fb_helper: driver-allocated fbdev helper, can be NULL
    241   1.9  riastrad  *
    242  1.17  riastrad  * This should be called from driver's drm &drm_driver.lastclose callback
    243   1.9  riastrad  * when implementing an fbcon on top of kms using this helper. This ensures that
    244   1.9  riastrad  * the user isn't greeted with a black screen when e.g. X dies.
    245   1.9  riastrad  *
    246   1.9  riastrad  * RETURNS:
    247   1.9  riastrad  * Zero if everything went ok, negative error code otherwise.
    248   1.5  riastrad  */
    249   1.9  riastrad int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
    250   1.1  riastrad {
    251   1.9  riastrad 	bool do_delayed;
    252   1.9  riastrad 	int ret;
    253   1.1  riastrad 
    254  1.17  riastrad 	if (!drm_fbdev_emulation || !fb_helper)
    255   1.9  riastrad 		return -ENODEV;
    256   1.1  riastrad 
    257  1.17  riastrad 	if (READ_ONCE(fb_helper->deferred_setup))
    258  1.17  riastrad 		return 0;
    259  1.17  riastrad 
    260  1.17  riastrad 	mutex_lock(&fb_helper->lock);
    261  1.17  riastrad 	/*
    262  1.17  riastrad 	 * TODO:
    263  1.17  riastrad 	 * We should bail out here if there is a master by dropping _force.
    264  1.17  riastrad 	 * Currently these igt tests fail if we do that:
    265  1.17  riastrad 	 * - kms_fbcon_fbt@psr
    266  1.17  riastrad 	 * - kms_fbcon_fbt@psr-suspend
    267  1.17  riastrad 	 *
    268  1.17  riastrad 	 * So first these tests need to be fixed so they drop master or don't
    269  1.17  riastrad 	 * have an fd open.
    270  1.17  riastrad 	 */
    271  1.17  riastrad 	ret = drm_client_modeset_commit_force(&fb_helper->client);
    272   1.1  riastrad 
    273   1.9  riastrad 	do_delayed = fb_helper->delayed_hotplug;
    274   1.9  riastrad 	if (do_delayed)
    275   1.9  riastrad 		fb_helper->delayed_hotplug = false;
    276  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
    277   1.1  riastrad 
    278   1.9  riastrad 	if (do_delayed)
    279   1.9  riastrad 		drm_fb_helper_hotplug_event(fb_helper);
    280  1.17  riastrad 
    281   1.9  riastrad 	return ret;
    282   1.1  riastrad }
    283   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
    284   1.1  riastrad 
    285   1.1  riastrad #ifdef CONFIG_MAGIC_SYSRQ
    286   1.9  riastrad /*
    287   1.9  riastrad  * restore fbcon display for all kms driver's using this helper, used for sysrq
    288   1.9  riastrad  * and panic handling.
    289   1.9  riastrad  */
    290   1.9  riastrad static bool drm_fb_helper_force_kernel_mode(void)
    291   1.9  riastrad {
    292   1.9  riastrad 	bool ret, error = false;
    293   1.9  riastrad 	struct drm_fb_helper *helper;
    294   1.9  riastrad 
    295   1.9  riastrad 	if (list_empty(&kernel_fb_helper_list))
    296   1.9  riastrad 		return false;
    297   1.9  riastrad 
    298   1.9  riastrad 	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
    299   1.9  riastrad 		struct drm_device *dev = helper->dev;
    300   1.9  riastrad 
    301   1.9  riastrad 		if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
    302   1.9  riastrad 			continue;
    303   1.9  riastrad 
    304  1.17  riastrad 		mutex_lock(&helper->lock);
    305  1.17  riastrad 		ret = drm_client_modeset_commit_force(&helper->client);
    306   1.9  riastrad 		if (ret)
    307   1.9  riastrad 			error = true;
    308  1.17  riastrad 		mutex_unlock(&helper->lock);
    309   1.9  riastrad 	}
    310   1.9  riastrad 	return error;
    311   1.9  riastrad }
    312   1.9  riastrad 
    313   1.1  riastrad static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
    314   1.1  riastrad {
    315   1.5  riastrad 	bool ret;
    316  1.17  riastrad 
    317   1.5  riastrad 	ret = drm_fb_helper_force_kernel_mode();
    318   1.5  riastrad 	if (ret == true)
    319   1.5  riastrad 		DRM_ERROR("Failed to restore crtc configuration\n");
    320   1.1  riastrad }
    321   1.1  riastrad static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
    322   1.1  riastrad 
    323   1.1  riastrad static void drm_fb_helper_sysrq(int dummy1)
    324   1.1  riastrad {
    325   1.1  riastrad 	schedule_work(&drm_fb_helper_restore_work);
    326   1.1  riastrad }
    327   1.1  riastrad 
    328   1.1  riastrad static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
    329   1.1  riastrad 	.handler = drm_fb_helper_sysrq,
    330   1.1  riastrad 	.help_msg = "force-fb(V)",
    331   1.1  riastrad 	.action_msg = "Restore framebuffer console",
    332   1.1  riastrad };
    333   1.1  riastrad #else
    334  1.15  riastrad static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
    335   1.1  riastrad #endif
    336   1.1  riastrad 
    337   1.2  riastrad #ifndef __NetBSD__		/* XXX fb info */
    338   1.1  riastrad static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
    339   1.1  riastrad {
    340   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
    341   1.1  riastrad 
    342  1.17  riastrad 	mutex_lock(&fb_helper->lock);
    343  1.17  riastrad 	drm_client_modeset_dpms(&fb_helper->client, dpms_mode);
    344  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
    345   1.1  riastrad }
    346   1.1  riastrad 
    347   1.5  riastrad /**
    348  1.17  riastrad  * drm_fb_helper_blank - implementation for &fb_ops.fb_blank
    349   1.5  riastrad  * @blank: desired blanking state
    350   1.5  riastrad  * @info: fbdev registered by the helper
    351   1.5  riastrad  */
    352   1.1  riastrad int drm_fb_helper_blank(int blank, struct fb_info *info)
    353   1.1  riastrad {
    354   1.9  riastrad 	if (oops_in_progress)
    355   1.9  riastrad 		return -EBUSY;
    356   1.9  riastrad 
    357   1.1  riastrad 	switch (blank) {
    358   1.1  riastrad 	/* Display: On; HSync: On, VSync: On */
    359   1.1  riastrad 	case FB_BLANK_UNBLANK:
    360   1.1  riastrad 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
    361   1.1  riastrad 		break;
    362   1.1  riastrad 	/* Display: Off; HSync: On, VSync: On */
    363   1.1  riastrad 	case FB_BLANK_NORMAL:
    364   1.1  riastrad 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
    365   1.1  riastrad 		break;
    366   1.1  riastrad 	/* Display: Off; HSync: Off, VSync: On */
    367   1.1  riastrad 	case FB_BLANK_HSYNC_SUSPEND:
    368   1.1  riastrad 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
    369   1.1  riastrad 		break;
    370   1.1  riastrad 	/* Display: Off; HSync: On, VSync: Off */
    371   1.1  riastrad 	case FB_BLANK_VSYNC_SUSPEND:
    372   1.1  riastrad 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
    373   1.1  riastrad 		break;
    374   1.1  riastrad 	/* Display: Off; HSync: Off, VSync: Off */
    375   1.1  riastrad 	case FB_BLANK_POWERDOWN:
    376   1.1  riastrad 		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
    377   1.1  riastrad 		break;
    378   1.1  riastrad 	}
    379   1.1  riastrad 	return 0;
    380   1.1  riastrad }
    381   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_blank);
    382   1.2  riastrad #endif
    383   1.1  riastrad 
    384  1.17  riastrad static void drm_fb_helper_resume_worker(struct work_struct *work)
    385  1.17  riastrad {
    386  1.20  riastrad #ifndef __NetBSD__		/* XXX fb suspend */
    387  1.17  riastrad 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
    388  1.17  riastrad 						    resume_work);
    389  1.17  riastrad 
    390  1.17  riastrad 	console_lock();
    391  1.17  riastrad 	fb_set_suspend(helper->fbdev, 0);
    392  1.17  riastrad 	console_unlock();
    393  1.20  riastrad #endif
    394  1.17  riastrad }
    395  1.17  riastrad 
    396  1.17  riastrad static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper,
    397  1.17  riastrad 					  struct drm_clip_rect *clip)
    398   1.1  riastrad {
    399  1.24  riastrad #ifndef __NetBSD__		/* XXX fb dirty */
    400  1.17  riastrad 	struct drm_framebuffer *fb = fb_helper->fb;
    401  1.17  riastrad 	unsigned int cpp = fb->format->cpp[0];
    402  1.17  riastrad 	size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
    403  1.20  riastrad 	void *src = (char *)fb_helper->fbdev->screen_buffer + offset;
    404  1.20  riastrad 	void *dst = (char *)fb_helper->buffer->vaddr + offset;
    405  1.17  riastrad 	size_t len = (clip->x2 - clip->x1) * cpp;
    406  1.17  riastrad 	unsigned int y;
    407  1.17  riastrad 
    408  1.17  riastrad 	for (y = clip->y1; y < clip->y2; y++) {
    409  1.17  riastrad 		memcpy(dst, src, len);
    410  1.20  riastrad 		src = (char *)src + fb->pitches[0];
    411  1.20  riastrad 		dst = (char *)dst + fb->pitches[0];
    412  1.17  riastrad 	}
    413  1.24  riastrad #endif
    414  1.17  riastrad }
    415  1.17  riastrad 
    416  1.17  riastrad static void drm_fb_helper_dirty_work(struct work_struct *work)
    417  1.17  riastrad {
    418  1.17  riastrad 	struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
    419  1.17  riastrad 						    dirty_work);
    420  1.17  riastrad 	struct drm_clip_rect *clip = &helper->dirty_clip;
    421  1.17  riastrad 	struct drm_clip_rect clip_copy;
    422  1.17  riastrad 	unsigned long flags;
    423  1.17  riastrad 	void *vaddr;
    424  1.17  riastrad 
    425  1.17  riastrad 	spin_lock_irqsave(&helper->dirty_lock, flags);
    426  1.17  riastrad 	clip_copy = *clip;
    427  1.17  riastrad 	clip->x1 = clip->y1 = ~0;
    428  1.17  riastrad 	clip->x2 = clip->y2 = 0;
    429  1.17  riastrad 	spin_unlock_irqrestore(&helper->dirty_lock, flags);
    430  1.17  riastrad 
    431  1.17  riastrad 	/* call dirty callback only when it has been really touched */
    432  1.17  riastrad 	if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2) {
    433  1.17  riastrad 
    434  1.17  riastrad 		/* Generic fbdev uses a shadow buffer */
    435  1.17  riastrad 		if (helper->buffer) {
    436  1.17  riastrad 			vaddr = drm_client_buffer_vmap(helper->buffer);
    437  1.17  riastrad 			if (IS_ERR(vaddr))
    438  1.17  riastrad 				return;
    439  1.17  riastrad 			drm_fb_helper_dirty_blit_real(helper, &clip_copy);
    440  1.17  riastrad 		}
    441  1.17  riastrad 		if (helper->fb->funcs->dirty)
    442  1.17  riastrad 			helper->fb->funcs->dirty(helper->fb, NULL, 0, 0,
    443  1.17  riastrad 						 &clip_copy, 1);
    444   1.1  riastrad 
    445  1.17  riastrad 		if (helper->buffer)
    446  1.17  riastrad 			drm_client_buffer_vunmap(helper->buffer);
    447   1.1  riastrad 	}
    448   1.1  riastrad }
    449   1.1  riastrad 
    450   1.5  riastrad /**
    451   1.9  riastrad  * drm_fb_helper_prepare - setup a drm_fb_helper structure
    452   1.9  riastrad  * @dev: DRM device
    453   1.9  riastrad  * @helper: driver-allocated fbdev helper structure to set up
    454   1.9  riastrad  * @funcs: pointer to structure of functions associate with this helper
    455   1.9  riastrad  *
    456   1.9  riastrad  * Sets up the bare minimum to make the framebuffer helper usable. This is
    457   1.9  riastrad  * useful to implement race-free initialization of the polling helpers.
    458   1.9  riastrad  */
    459   1.9  riastrad void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
    460   1.9  riastrad 			   const struct drm_fb_helper_funcs *funcs)
    461   1.9  riastrad {
    462   1.9  riastrad 	INIT_LIST_HEAD(&helper->kernel_fb_list);
    463  1.17  riastrad 	spin_lock_init(&helper->dirty_lock);
    464  1.17  riastrad 	INIT_WORK(&helper->resume_work, drm_fb_helper_resume_worker);
    465  1.17  riastrad 	INIT_WORK(&helper->dirty_work, drm_fb_helper_dirty_work);
    466  1.17  riastrad 	helper->dirty_clip.x1 = helper->dirty_clip.y1 = ~0;
    467  1.17  riastrad 	mutex_init(&helper->lock);
    468   1.9  riastrad 	helper->funcs = funcs;
    469   1.9  riastrad 	helper->dev = dev;
    470   1.9  riastrad }
    471   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_prepare);
    472   1.9  riastrad 
    473   1.9  riastrad /**
    474  1.17  riastrad  * drm_fb_helper_init - initialize a &struct drm_fb_helper
    475   1.5  riastrad  * @dev: drm device
    476   1.5  riastrad  * @fb_helper: driver-allocated fbdev helper structure to initialize
    477  1.17  riastrad  * @max_conn_count: max connector count (not used)
    478   1.5  riastrad  *
    479   1.5  riastrad  * This allocates the structures for the fbdev helper with the given limits.
    480   1.5  riastrad  * Note that this won't yet touch the hardware (through the driver interfaces)
    481   1.5  riastrad  * nor register the fbdev. This is only done in drm_fb_helper_initial_config()
    482   1.5  riastrad  * to allow driver writes more control over the exact init sequence.
    483   1.5  riastrad  *
    484   1.9  riastrad  * Drivers must call drm_fb_helper_prepare() before calling this function.
    485   1.5  riastrad  *
    486   1.5  riastrad  * RETURNS:
    487   1.5  riastrad  * Zero if everything went ok, nonzero otherwise.
    488   1.5  riastrad  */
    489   1.1  riastrad int drm_fb_helper_init(struct drm_device *dev,
    490   1.1  riastrad 		       struct drm_fb_helper *fb_helper,
    491  1.17  riastrad 		       int max_conn_count)
    492   1.1  riastrad {
    493  1.17  riastrad 	int ret;
    494   1.1  riastrad 
    495  1.17  riastrad 	if (!drm_fbdev_emulation) {
    496  1.17  riastrad 		dev->fb_helper = fb_helper;
    497   1.9  riastrad 		return 0;
    498   1.1  riastrad 	}
    499   1.1  riastrad 
    500  1.17  riastrad 	/*
    501  1.17  riastrad 	 * If this is not the generic fbdev client, initialize a drm_client
    502  1.17  riastrad 	 * without callbacks so we can use the modesets.
    503  1.17  riastrad 	 */
    504  1.17  riastrad 	if (!fb_helper->client.funcs) {
    505  1.17  riastrad 		ret = drm_client_init(dev, &fb_helper->client, "drm_fb_helper", NULL);
    506  1.24  riastrad 		if (ret) {
    507  1.24  riastrad 			/*
    508  1.24  riastrad 			 * XXX Undo what drm_fb_helper_prepare did
    509  1.24  riastrad 			 * since the caller will not be going through
    510  1.24  riastrad 			 * drm_fb_helper_fini.
    511  1.24  riastrad 			 */
    512  1.24  riastrad 			mutex_destroy(&fb_helper->lock);
    513  1.24  riastrad 			spin_lock_destroy(&fb_helper->dirty_lock);
    514  1.17  riastrad 			return ret;
    515  1.24  riastrad 		}
    516   1.1  riastrad 	}
    517   1.1  riastrad 
    518  1.17  riastrad 	dev->fb_helper = fb_helper;
    519   1.9  riastrad 
    520   1.1  riastrad 	return 0;
    521   1.1  riastrad }
    522   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_init);
    523   1.1  riastrad 
    524   1.9  riastrad /**
    525   1.9  riastrad  * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members
    526   1.9  riastrad  * @fb_helper: driver-allocated fbdev helper
    527   1.9  riastrad  *
    528   1.9  riastrad  * A helper to alloc fb_info and the members cmap and apertures. Called
    529  1.17  riastrad  * by the driver within the fb_probe fb_helper callback function. Drivers do not
    530  1.17  riastrad  * need to release the allocated fb_info structure themselves, this is
    531  1.17  riastrad  * automatically done when calling drm_fb_helper_fini().
    532   1.9  riastrad  *
    533   1.9  riastrad  * RETURNS:
    534   1.9  riastrad  * fb_info pointer if things went okay, pointer containing error code
    535   1.9  riastrad  * otherwise
    536   1.9  riastrad  */
    537  1.24  riastrad #ifndef __NetBSD__		/* XXX fb info */
    538   1.9  riastrad struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
    539   1.9  riastrad {
    540   1.9  riastrad 	struct device *dev = fb_helper->dev->dev;
    541   1.9  riastrad 	struct fb_info *info;
    542   1.9  riastrad 	int ret;
    543   1.9  riastrad 
    544   1.9  riastrad 	info = framebuffer_alloc(0, dev);
    545   1.9  riastrad 	if (!info)
    546   1.9  riastrad 		return ERR_PTR(-ENOMEM);
    547   1.9  riastrad 
    548   1.9  riastrad 	ret = fb_alloc_cmap(&info->cmap, 256, 0);
    549   1.9  riastrad 	if (ret)
    550   1.9  riastrad 		goto err_release;
    551   1.9  riastrad 
    552   1.9  riastrad 	info->apertures = alloc_apertures(1);
    553   1.9  riastrad 	if (!info->apertures) {
    554   1.9  riastrad 		ret = -ENOMEM;
    555   1.9  riastrad 		goto err_free_cmap;
    556   1.9  riastrad 	}
    557   1.9  riastrad 
    558   1.9  riastrad 	fb_helper->fbdev = info;
    559  1.17  riastrad 	info->skip_vt_switch = true;
    560   1.9  riastrad 
    561   1.9  riastrad 	return info;
    562   1.9  riastrad 
    563   1.9  riastrad err_free_cmap:
    564   1.9  riastrad 	fb_dealloc_cmap(&info->cmap);
    565   1.9  riastrad err_release:
    566   1.9  riastrad 	framebuffer_release(info);
    567   1.9  riastrad 	return ERR_PTR(ret);
    568   1.9  riastrad }
    569   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
    570  1.24  riastrad #endif
    571   1.9  riastrad 
    572   1.9  riastrad /**
    573   1.9  riastrad  * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device
    574  1.17  riastrad  * @fb_helper: driver-allocated fbdev helper, can be NULL
    575   1.9  riastrad  *
    576   1.9  riastrad  * A wrapper around unregister_framebuffer, to release the fb_info
    577  1.17  riastrad  * framebuffer device. This must be called before releasing all resources for
    578  1.17  riastrad  * @fb_helper by calling drm_fb_helper_fini().
    579   1.9  riastrad  */
    580   1.9  riastrad void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper)
    581   1.9  riastrad {
    582  1.24  riastrad #ifdef __NetBSD__
    583  1.24  riastrad 	/* XXX errno NetBSD->Linux */
    584  1.24  riastrad 	int ret = -config_detach(fb_helper->fbdev, DETACH_FORCE);
    585  1.24  riastrad 	if (ret)
    586  1.24  riastrad 		DRM_ERROR("failed to detach drm framebuffer: %d\n", ret);
    587  1.24  riastrad #else
    588   1.9  riastrad 	if (fb_helper && fb_helper->fbdev)
    589   1.9  riastrad 		unregister_framebuffer(fb_helper->fbdev);
    590  1.24  riastrad #endif
    591   1.9  riastrad }
    592   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
    593   1.9  riastrad 
    594   1.9  riastrad /**
    595  1.17  riastrad  * drm_fb_helper_fini - finialize a &struct drm_fb_helper
    596  1.17  riastrad  * @fb_helper: driver-allocated fbdev helper, can be NULL
    597   1.9  riastrad  *
    598  1.17  riastrad  * This cleans up all remaining resources associated with @fb_helper.
    599   1.9  riastrad  */
    600  1.17  riastrad void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
    601   1.9  riastrad {
    602  1.24  riastrad #ifndef __NetBSD__
    603  1.17  riastrad 	struct fb_info *info;
    604  1.24  riastrad #endif
    605   1.9  riastrad 
    606  1.17  riastrad 	if (!fb_helper)
    607  1.17  riastrad 		return;
    608   1.9  riastrad 
    609  1.17  riastrad 	fb_helper->dev->fb_helper = NULL;
    610  1.10  riastrad 
    611   1.9  riastrad 	if (!drm_fbdev_emulation)
    612   1.9  riastrad 		return;
    613   1.9  riastrad 
    614  1.17  riastrad 	cancel_work_sync(&fb_helper->resume_work);
    615  1.17  riastrad 	cancel_work_sync(&fb_helper->dirty_work);
    616  1.17  riastrad 
    617  1.24  riastrad #ifndef __NetBSD__
    618  1.17  riastrad 	info = fb_helper->fbdev;
    619  1.17  riastrad 	if (info) {
    620  1.17  riastrad 		if (info->cmap.len)
    621  1.17  riastrad 			fb_dealloc_cmap(&info->cmap);
    622  1.17  riastrad 		framebuffer_release(info);
    623  1.17  riastrad 	}
    624  1.24  riastrad #endif
    625  1.17  riastrad 	fb_helper->fbdev = NULL;
    626  1.17  riastrad 
    627  1.17  riastrad 	mutex_lock(&kernel_fb_helper_lock);
    628   1.1  riastrad 	if (!list_empty(&fb_helper->kernel_fb_list)) {
    629   1.1  riastrad 		list_del(&fb_helper->kernel_fb_list);
    630  1.18  riastrad 		if (list_empty(&kernel_fb_helper_list))
    631   1.1  riastrad 			unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
    632   1.1  riastrad 	}
    633  1.17  riastrad 	mutex_unlock(&kernel_fb_helper_lock);
    634   1.1  riastrad 
    635  1.17  riastrad 	mutex_destroy(&fb_helper->lock);
    636  1.24  riastrad 	spin_lock_destroy(&fb_helper->dirty_lock);
    637   1.1  riastrad 
    638  1.17  riastrad 	if (!fb_helper->client.funcs)
    639  1.17  riastrad 		drm_client_release(&fb_helper->client);
    640   1.1  riastrad }
    641   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_fini);
    642   1.1  riastrad 
    643  1.24  riastrad #ifndef __NetBSD__		/* XXX fb dirty */
    644  1.24  riastrad 
    645  1.17  riastrad static bool drm_fbdev_use_shadow_fb(struct drm_fb_helper *fb_helper)
    646  1.14  riastrad {
    647  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
    648  1.17  riastrad 	struct drm_framebuffer *fb = fb_helper->fb;
    649  1.17  riastrad 
    650  1.17  riastrad 	return dev->mode_config.prefer_shadow_fbdev ||
    651  1.17  riastrad 	       dev->mode_config.prefer_shadow ||
    652  1.17  riastrad 	       fb->funcs->dirty;
    653  1.14  riastrad }
    654  1.17  riastrad 
    655  1.17  riastrad static void drm_fb_helper_dirty(struct fb_info *info, u32 x, u32 y,
    656  1.17  riastrad 				u32 width, u32 height)
    657   1.9  riastrad {
    658  1.17  riastrad 	struct drm_fb_helper *helper = info->par;
    659  1.17  riastrad 	struct drm_clip_rect *clip = &helper->dirty_clip;
    660  1.17  riastrad 	unsigned long flags;
    661  1.17  riastrad 
    662  1.17  riastrad 	if (!drm_fbdev_use_shadow_fb(helper))
    663  1.17  riastrad 		return;
    664  1.17  riastrad 
    665  1.17  riastrad 	spin_lock_irqsave(&helper->dirty_lock, flags);
    666  1.17  riastrad 	clip->x1 = min_t(u32, clip->x1, x);
    667  1.17  riastrad 	clip->y1 = min_t(u32, clip->y1, y);
    668  1.17  riastrad 	clip->x2 = max_t(u32, clip->x2, x + width);
    669  1.17  riastrad 	clip->y2 = max_t(u32, clip->y2, y + height);
    670  1.17  riastrad 	spin_unlock_irqrestore(&helper->dirty_lock, flags);
    671  1.17  riastrad 
    672  1.17  riastrad 	schedule_work(&helper->dirty_work);
    673  1.17  riastrad }
    674  1.17  riastrad 
    675  1.24  riastrad #endif
    676  1.24  riastrad 
    677  1.20  riastrad #ifndef __NetBSD__		/* XXX fb deferred */
    678  1.20  riastrad 
    679  1.17  riastrad /**
    680  1.17  riastrad  * drm_fb_helper_deferred_io() - fbdev deferred_io callback function
    681  1.17  riastrad  * @info: fb_info struct pointer
    682  1.17  riastrad  * @pagelist: list of dirty mmap framebuffer pages
    683  1.17  riastrad  *
    684  1.17  riastrad  * This function is used as the &fb_deferred_io.deferred_io
    685  1.17  riastrad  * callback function for flushing the fbdev mmap writes.
    686  1.17  riastrad  */
    687  1.17  riastrad void drm_fb_helper_deferred_io(struct fb_info *info,
    688  1.17  riastrad 			       struct list_head *pagelist)
    689  1.17  riastrad {
    690  1.17  riastrad 	unsigned long start, end, min, max;
    691  1.17  riastrad 	struct page *page;
    692  1.17  riastrad 	u32 y1, y2;
    693  1.17  riastrad 
    694  1.17  riastrad 	min = ULONG_MAX;
    695  1.17  riastrad 	max = 0;
    696  1.17  riastrad 	list_for_each_entry(page, pagelist, lru) {
    697  1.17  riastrad 		start = page->index << PAGE_SHIFT;
    698  1.17  riastrad 		end = start + PAGE_SIZE - 1;
    699  1.17  riastrad 		min = min(min, start);
    700  1.17  riastrad 		max = max(max, end);
    701  1.17  riastrad 	}
    702  1.17  riastrad 
    703  1.17  riastrad 	if (min < max) {
    704  1.17  riastrad 		y1 = min / info->fix.line_length;
    705  1.17  riastrad 		y2 = min_t(u32, DIV_ROUND_UP(max, info->fix.line_length),
    706  1.17  riastrad 			   info->var.yres);
    707  1.17  riastrad 		drm_fb_helper_dirty(info, 0, y1, info->var.xres, y2 - y1);
    708  1.17  riastrad 	}
    709  1.17  riastrad }
    710  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_deferred_io);
    711   1.9  riastrad 
    712   1.9  riastrad /**
    713   1.9  riastrad  * drm_fb_helper_sys_read - wrapper around fb_sys_read
    714   1.9  riastrad  * @info: fb_info struct pointer
    715   1.9  riastrad  * @buf: userspace buffer to read from framebuffer memory
    716   1.9  riastrad  * @count: number of bytes to read from framebuffer memory
    717   1.9  riastrad  * @ppos: read offset within framebuffer memory
    718   1.9  riastrad  *
    719   1.9  riastrad  * A wrapper around fb_sys_read implemented by fbdev core
    720   1.9  riastrad  */
    721   1.9  riastrad ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
    722   1.9  riastrad 			       size_t count, loff_t *ppos)
    723   1.9  riastrad {
    724   1.9  riastrad 	return fb_sys_read(info, buf, count, ppos);
    725   1.9  riastrad }
    726   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_sys_read);
    727   1.9  riastrad 
    728   1.9  riastrad /**
    729   1.9  riastrad  * drm_fb_helper_sys_write - wrapper around fb_sys_write
    730   1.9  riastrad  * @info: fb_info struct pointer
    731   1.9  riastrad  * @buf: userspace buffer to write to framebuffer memory
    732   1.9  riastrad  * @count: number of bytes to write to framebuffer memory
    733   1.9  riastrad  * @ppos: write offset within framebuffer memory
    734   1.9  riastrad  *
    735   1.9  riastrad  * A wrapper around fb_sys_write implemented by fbdev core
    736   1.9  riastrad  */
    737   1.9  riastrad ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
    738   1.9  riastrad 				size_t count, loff_t *ppos)
    739   1.9  riastrad {
    740  1.17  riastrad 	ssize_t ret;
    741  1.17  riastrad 
    742  1.17  riastrad 	ret = fb_sys_write(info, buf, count, ppos);
    743  1.17  riastrad 	if (ret > 0)
    744  1.17  riastrad 		drm_fb_helper_dirty(info, 0, 0, info->var.xres,
    745  1.17  riastrad 				    info->var.yres);
    746  1.17  riastrad 
    747  1.17  riastrad 	return ret;
    748   1.9  riastrad }
    749   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_sys_write);
    750   1.9  riastrad 
    751   1.9  riastrad /**
    752   1.9  riastrad  * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect
    753   1.9  riastrad  * @info: fbdev registered by the helper
    754   1.9  riastrad  * @rect: info about rectangle to fill
    755   1.9  riastrad  *
    756   1.9  riastrad  * A wrapper around sys_fillrect implemented by fbdev core
    757   1.9  riastrad  */
    758   1.9  riastrad void drm_fb_helper_sys_fillrect(struct fb_info *info,
    759   1.9  riastrad 				const struct fb_fillrect *rect)
    760   1.9  riastrad {
    761   1.9  riastrad 	sys_fillrect(info, rect);
    762  1.17  riastrad 	drm_fb_helper_dirty(info, rect->dx, rect->dy,
    763  1.17  riastrad 			    rect->width, rect->height);
    764   1.9  riastrad }
    765   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_sys_fillrect);
    766   1.9  riastrad 
    767   1.9  riastrad /**
    768   1.9  riastrad  * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea
    769   1.9  riastrad  * @info: fbdev registered by the helper
    770   1.9  riastrad  * @area: info about area to copy
    771   1.9  riastrad  *
    772   1.9  riastrad  * A wrapper around sys_copyarea implemented by fbdev core
    773   1.9  riastrad  */
    774   1.9  riastrad void drm_fb_helper_sys_copyarea(struct fb_info *info,
    775   1.9  riastrad 				const struct fb_copyarea *area)
    776   1.9  riastrad {
    777   1.9  riastrad 	sys_copyarea(info, area);
    778  1.17  riastrad 	drm_fb_helper_dirty(info, area->dx, area->dy,
    779  1.17  riastrad 			    area->width, area->height);
    780   1.9  riastrad }
    781   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_sys_copyarea);
    782   1.9  riastrad 
    783   1.9  riastrad /**
    784   1.9  riastrad  * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit
    785   1.9  riastrad  * @info: fbdev registered by the helper
    786   1.9  riastrad  * @image: info about image to blit
    787   1.9  riastrad  *
    788   1.9  riastrad  * A wrapper around sys_imageblit implemented by fbdev core
    789   1.9  riastrad  */
    790   1.9  riastrad void drm_fb_helper_sys_imageblit(struct fb_info *info,
    791   1.9  riastrad 				 const struct fb_image *image)
    792   1.9  riastrad {
    793   1.9  riastrad 	sys_imageblit(info, image);
    794  1.17  riastrad 	drm_fb_helper_dirty(info, image->dx, image->dy,
    795  1.17  riastrad 			    image->width, image->height);
    796   1.9  riastrad }
    797   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
    798   1.9  riastrad 
    799   1.9  riastrad /**
    800   1.9  riastrad  * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect
    801   1.9  riastrad  * @info: fbdev registered by the helper
    802   1.9  riastrad  * @rect: info about rectangle to fill
    803   1.9  riastrad  *
    804  1.17  riastrad  * A wrapper around cfb_fillrect implemented by fbdev core
    805   1.9  riastrad  */
    806   1.9  riastrad void drm_fb_helper_cfb_fillrect(struct fb_info *info,
    807   1.9  riastrad 				const struct fb_fillrect *rect)
    808   1.9  riastrad {
    809   1.9  riastrad 	cfb_fillrect(info, rect);
    810  1.17  riastrad 	drm_fb_helper_dirty(info, rect->dx, rect->dy,
    811  1.17  riastrad 			    rect->width, rect->height);
    812   1.9  riastrad }
    813   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect);
    814   1.9  riastrad 
    815   1.9  riastrad /**
    816   1.9  riastrad  * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea
    817   1.9  riastrad  * @info: fbdev registered by the helper
    818   1.9  riastrad  * @area: info about area to copy
    819   1.9  riastrad  *
    820   1.9  riastrad  * A wrapper around cfb_copyarea implemented by fbdev core
    821   1.9  riastrad  */
    822   1.9  riastrad void drm_fb_helper_cfb_copyarea(struct fb_info *info,
    823   1.9  riastrad 				const struct fb_copyarea *area)
    824   1.9  riastrad {
    825   1.9  riastrad 	cfb_copyarea(info, area);
    826  1.17  riastrad 	drm_fb_helper_dirty(info, area->dx, area->dy,
    827  1.17  riastrad 			    area->width, area->height);
    828   1.9  riastrad }
    829   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea);
    830   1.9  riastrad 
    831   1.9  riastrad /**
    832   1.9  riastrad  * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit
    833   1.9  riastrad  * @info: fbdev registered by the helper
    834   1.9  riastrad  * @image: info about image to blit
    835   1.9  riastrad  *
    836   1.9  riastrad  * A wrapper around cfb_imageblit implemented by fbdev core
    837   1.9  riastrad  */
    838   1.9  riastrad void drm_fb_helper_cfb_imageblit(struct fb_info *info,
    839   1.9  riastrad 				 const struct fb_image *image)
    840   1.9  riastrad {
    841   1.9  riastrad 	cfb_imageblit(info, image);
    842  1.17  riastrad 	drm_fb_helper_dirty(info, image->dx, image->dy,
    843  1.17  riastrad 			    image->width, image->height);
    844   1.9  riastrad }
    845   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit);
    846  1.20  riastrad #endif	/* __NetBSD__ */
    847   1.9  riastrad 
    848  1.17  riastrad #ifdef __NetBSD__		/* XXX fb info */
    849  1.24  riastrad void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
    850  1.17  riastrad {
    851  1.17  riastrad }
    852  1.17  riastrad #else
    853   1.9  riastrad /**
    854   1.9  riastrad  * drm_fb_helper_set_suspend - wrapper around fb_set_suspend
    855  1.17  riastrad  * @fb_helper: driver-allocated fbdev helper, can be NULL
    856  1.17  riastrad  * @suspend: whether to suspend or resume
    857   1.9  riastrad  *
    858  1.17  riastrad  * A wrapper around fb_set_suspend implemented by fbdev core.
    859  1.17  riastrad  * Use drm_fb_helper_set_suspend_unlocked() if you don't need to take
    860  1.17  riastrad  * the lock yourself
    861   1.9  riastrad  */
    862  1.17  riastrad void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, bool suspend)
    863   1.9  riastrad {
    864   1.9  riastrad 	if (fb_helper && fb_helper->fbdev)
    865  1.17  riastrad 		fb_set_suspend(fb_helper->fbdev, suspend);
    866   1.9  riastrad }
    867   1.9  riastrad EXPORT_SYMBOL(drm_fb_helper_set_suspend);
    868  1.17  riastrad #endif
    869  1.17  riastrad 
    870  1.17  riastrad /**
    871  1.17  riastrad  * drm_fb_helper_set_suspend_unlocked - wrapper around fb_set_suspend that also
    872  1.17  riastrad  *                                      takes the console lock
    873  1.17  riastrad  * @fb_helper: driver-allocated fbdev helper, can be NULL
    874  1.17  riastrad  * @suspend: whether to suspend or resume
    875  1.17  riastrad  *
    876  1.17  riastrad  * A wrapper around fb_set_suspend() that takes the console lock. If the lock
    877  1.17  riastrad  * isn't available on resume, a worker is tasked with waiting for the lock
    878  1.17  riastrad  * to become available. The console lock can be pretty contented on resume
    879  1.17  riastrad  * due to all the printk activity.
    880  1.17  riastrad  *
    881  1.17  riastrad  * This function can be called multiple times with the same state since
    882  1.17  riastrad  * &fb_info.state is checked to see if fbdev is running or not before locking.
    883  1.17  riastrad  *
    884  1.17  riastrad  * Use drm_fb_helper_set_suspend() if you need to take the lock yourself.
    885  1.17  riastrad  */
    886  1.17  riastrad void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
    887  1.17  riastrad 					bool suspend)
    888  1.17  riastrad {
    889  1.17  riastrad 	if (!fb_helper || !fb_helper->fbdev)
    890  1.17  riastrad 		return;
    891  1.17  riastrad 
    892  1.17  riastrad 	/* make sure there's no pending/ongoing resume */
    893  1.17  riastrad 	flush_work(&fb_helper->resume_work);
    894  1.17  riastrad 
    895  1.24  riastrad #ifndef __NetBSD__		/* XXX fb suspend */
    896  1.17  riastrad 	if (suspend) {
    897  1.17  riastrad 		if (fb_helper->fbdev->state != FBINFO_STATE_RUNNING)
    898  1.17  riastrad 			return;
    899  1.17  riastrad 
    900  1.17  riastrad 		console_lock();
    901  1.17  riastrad 
    902  1.17  riastrad 	} else {
    903  1.17  riastrad 		if (fb_helper->fbdev->state == FBINFO_STATE_RUNNING)
    904  1.17  riastrad 			return;
    905  1.17  riastrad 
    906  1.17  riastrad 		if (!console_trylock()) {
    907  1.17  riastrad 			schedule_work(&fb_helper->resume_work);
    908  1.17  riastrad 			return;
    909  1.17  riastrad 		}
    910  1.17  riastrad 	}
    911  1.17  riastrad 
    912  1.17  riastrad 	fb_set_suspend(fb_helper->fbdev, suspend);
    913  1.17  riastrad 	console_unlock();
    914  1.24  riastrad #endif
    915  1.17  riastrad }
    916  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_set_suspend_unlocked);
    917   1.9  riastrad 
    918  1.24  riastrad #ifndef __NetBSD__
    919  1.24  riastrad 
    920  1.17  riastrad static int setcmap_pseudo_palette(struct fb_cmap *cmap, struct fb_info *info)
    921   1.1  riastrad {
    922  1.17  riastrad 	u32 *palette = (u32 *)info->pseudo_palette;
    923  1.17  riastrad 	int i;
    924  1.17  riastrad 
    925  1.17  riastrad 	if (cmap->start + cmap->len > 16)
    926  1.17  riastrad 		return -EINVAL;
    927   1.1  riastrad 
    928  1.17  riastrad 	for (i = 0; i < cmap->len; ++i) {
    929  1.17  riastrad 		u16 red = cmap->red[i];
    930  1.17  riastrad 		u16 green = cmap->green[i];
    931  1.17  riastrad 		u16 blue = cmap->blue[i];
    932   1.1  riastrad 		u32 value;
    933  1.17  riastrad 
    934  1.17  riastrad 		red >>= 16 - info->var.red.length;
    935  1.17  riastrad 		green >>= 16 - info->var.green.length;
    936  1.17  riastrad 		blue >>= 16 - info->var.blue.length;
    937   1.1  riastrad 		value = (red << info->var.red.offset) |
    938   1.1  riastrad 			(green << info->var.green.offset) |
    939   1.1  riastrad 			(blue << info->var.blue.offset);
    940   1.1  riastrad 		if (info->var.transp.length > 0) {
    941   1.1  riastrad 			u32 mask = (1 << info->var.transp.length) - 1;
    942  1.17  riastrad 
    943   1.1  riastrad 			mask <<= info->var.transp.offset;
    944   1.1  riastrad 			value |= mask;
    945   1.1  riastrad 		}
    946  1.17  riastrad 		palette[cmap->start + i] = value;
    947   1.1  riastrad 	}
    948   1.1  riastrad 
    949  1.17  riastrad 	return 0;
    950  1.17  riastrad }
    951   1.5  riastrad 
    952  1.17  riastrad static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info)
    953  1.17  riastrad {
    954  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
    955  1.17  riastrad 	struct drm_mode_set *modeset;
    956  1.17  riastrad 	struct drm_crtc *crtc;
    957  1.17  riastrad 	u16 *r, *g, *b;
    958  1.17  riastrad 	int ret = 0;
    959   1.1  riastrad 
    960  1.17  riastrad 	drm_modeset_lock_all(fb_helper->dev);
    961  1.17  riastrad 	drm_client_for_each_modeset(modeset, &fb_helper->client) {
    962  1.17  riastrad 		crtc = modeset->crtc;
    963  1.17  riastrad 		if (!crtc->funcs->gamma_set || !crtc->gamma_size)
    964  1.17  riastrad 			return -EINVAL;
    965   1.1  riastrad 
    966  1.17  riastrad 		if (cmap->start + cmap->len > crtc->gamma_size)
    967   1.1  riastrad 			return -EINVAL;
    968   1.1  riastrad 
    969  1.17  riastrad 		r = crtc->gamma_store;
    970  1.17  riastrad 		g = r + crtc->gamma_size;
    971  1.17  riastrad 		b = g + crtc->gamma_size;
    972  1.17  riastrad 
    973  1.17  riastrad 		memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
    974  1.17  riastrad 		memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
    975  1.17  riastrad 		memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
    976  1.17  riastrad 
    977  1.17  riastrad 		ret = crtc->funcs->gamma_set(crtc, r, g, b,
    978  1.17  riastrad 					     crtc->gamma_size, NULL);
    979  1.17  riastrad 		if (ret)
    980  1.17  riastrad 			return ret;
    981  1.17  riastrad 	}
    982  1.17  riastrad 	drm_modeset_unlock_all(fb_helper->dev);
    983  1.17  riastrad 
    984  1.17  riastrad 	return ret;
    985  1.17  riastrad }
    986  1.17  riastrad 
    987  1.17  riastrad static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
    988  1.17  riastrad 						       struct fb_cmap *cmap)
    989  1.17  riastrad {
    990  1.17  riastrad 	struct drm_device *dev = crtc->dev;
    991  1.17  riastrad 	struct drm_property_blob *gamma_lut;
    992  1.17  riastrad 	struct drm_color_lut *lut;
    993  1.17  riastrad 	int size = crtc->gamma_size;
    994  1.17  riastrad 	int i;
    995  1.17  riastrad 
    996  1.17  riastrad 	if (!size || cmap->start + cmap->len > size)
    997  1.17  riastrad 		return ERR_PTR(-EINVAL);
    998  1.17  riastrad 
    999  1.17  riastrad 	gamma_lut = drm_property_create_blob(dev, sizeof(*lut) * size, NULL);
   1000  1.17  riastrad 	if (IS_ERR(gamma_lut))
   1001  1.17  riastrad 		return gamma_lut;
   1002  1.17  riastrad 
   1003  1.17  riastrad 	lut = gamma_lut->data;
   1004  1.17  riastrad 	if (cmap->start || cmap->len != size) {
   1005  1.17  riastrad 		u16 *r = crtc->gamma_store;
   1006  1.17  riastrad 		u16 *g = r + crtc->gamma_size;
   1007  1.17  riastrad 		u16 *b = g + crtc->gamma_size;
   1008   1.1  riastrad 
   1009  1.17  riastrad 		for (i = 0; i < cmap->start; i++) {
   1010  1.17  riastrad 			lut[i].red = r[i];
   1011  1.17  riastrad 			lut[i].green = g[i];
   1012  1.17  riastrad 			lut[i].blue = b[i];
   1013   1.1  riastrad 		}
   1014  1.17  riastrad 		for (i = cmap->start + cmap->len; i < size; i++) {
   1015  1.17  riastrad 			lut[i].red = r[i];
   1016  1.17  riastrad 			lut[i].green = g[i];
   1017  1.17  riastrad 			lut[i].blue = b[i];
   1018  1.17  riastrad 		}
   1019  1.17  riastrad 	}
   1020  1.17  riastrad 
   1021  1.17  riastrad 	for (i = 0; i < cmap->len; i++) {
   1022  1.17  riastrad 		lut[cmap->start + i].red = cmap->red[i];
   1023  1.17  riastrad 		lut[cmap->start + i].green = cmap->green[i];
   1024  1.17  riastrad 		lut[cmap->start + i].blue = cmap->blue[i];
   1025  1.17  riastrad 	}
   1026  1.17  riastrad 
   1027  1.17  riastrad 	return gamma_lut;
   1028  1.17  riastrad }
   1029  1.17  riastrad 
   1030  1.17  riastrad static int setcmap_atomic(struct fb_cmap *cmap, struct fb_info *info)
   1031  1.17  riastrad {
   1032  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1033  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
   1034  1.17  riastrad 	struct drm_property_blob *gamma_lut = NULL;
   1035  1.17  riastrad 	struct drm_modeset_acquire_ctx ctx;
   1036  1.17  riastrad 	struct drm_crtc_state *crtc_state;
   1037  1.17  riastrad 	struct drm_atomic_state *state;
   1038  1.17  riastrad 	struct drm_mode_set *modeset;
   1039  1.17  riastrad 	struct drm_crtc *crtc;
   1040  1.17  riastrad 	u16 *r, *g, *b;
   1041  1.17  riastrad 	bool replaced;
   1042  1.17  riastrad 	int ret = 0;
   1043  1.17  riastrad 
   1044  1.17  riastrad 	drm_modeset_acquire_init(&ctx, 0);
   1045  1.17  riastrad 
   1046  1.17  riastrad 	state = drm_atomic_state_alloc(dev);
   1047  1.17  riastrad 	if (!state) {
   1048  1.17  riastrad 		ret = -ENOMEM;
   1049  1.17  riastrad 		goto out_ctx;
   1050  1.17  riastrad 	}
   1051  1.17  riastrad 
   1052  1.17  riastrad 	state->acquire_ctx = &ctx;
   1053  1.17  riastrad retry:
   1054  1.17  riastrad 	drm_client_for_each_modeset(modeset, &fb_helper->client) {
   1055  1.17  riastrad 		crtc = modeset->crtc;
   1056  1.17  riastrad 
   1057  1.17  riastrad 		if (!gamma_lut)
   1058  1.17  riastrad 			gamma_lut = setcmap_new_gamma_lut(crtc, cmap);
   1059  1.17  riastrad 		if (IS_ERR(gamma_lut)) {
   1060  1.17  riastrad 			ret = PTR_ERR(gamma_lut);
   1061  1.17  riastrad 			gamma_lut = NULL;
   1062  1.17  riastrad 			goto out_state;
   1063  1.17  riastrad 		}
   1064  1.17  riastrad 
   1065  1.17  riastrad 		crtc_state = drm_atomic_get_crtc_state(state, crtc);
   1066  1.17  riastrad 		if (IS_ERR(crtc_state)) {
   1067  1.17  riastrad 			ret = PTR_ERR(crtc_state);
   1068  1.17  riastrad 			goto out_state;
   1069  1.17  riastrad 		}
   1070  1.17  riastrad 
   1071  1.17  riastrad 		replaced  = drm_property_replace_blob(&crtc_state->degamma_lut,
   1072  1.17  riastrad 						      NULL);
   1073  1.17  riastrad 		replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL);
   1074  1.17  riastrad 		replaced |= drm_property_replace_blob(&crtc_state->gamma_lut,
   1075  1.17  riastrad 						      gamma_lut);
   1076  1.17  riastrad 		crtc_state->color_mgmt_changed |= replaced;
   1077  1.17  riastrad 	}
   1078  1.17  riastrad 
   1079  1.17  riastrad 	ret = drm_atomic_commit(state);
   1080  1.17  riastrad 	if (ret)
   1081  1.17  riastrad 		goto out_state;
   1082  1.17  riastrad 
   1083  1.17  riastrad 	drm_client_for_each_modeset(modeset, &fb_helper->client) {
   1084  1.17  riastrad 		crtc = modeset->crtc;
   1085  1.17  riastrad 
   1086  1.17  riastrad 		r = crtc->gamma_store;
   1087  1.17  riastrad 		g = r + crtc->gamma_size;
   1088  1.17  riastrad 		b = g + crtc->gamma_size;
   1089  1.17  riastrad 
   1090  1.17  riastrad 		memcpy(r + cmap->start, cmap->red, cmap->len * sizeof(*r));
   1091  1.17  riastrad 		memcpy(g + cmap->start, cmap->green, cmap->len * sizeof(*g));
   1092  1.17  riastrad 		memcpy(b + cmap->start, cmap->blue, cmap->len * sizeof(*b));
   1093   1.1  riastrad 	}
   1094   1.1  riastrad 
   1095  1.17  riastrad out_state:
   1096  1.17  riastrad 	if (ret == -EDEADLK)
   1097  1.17  riastrad 		goto backoff;
   1098  1.17  riastrad 
   1099  1.17  riastrad 	drm_property_blob_put(gamma_lut);
   1100  1.17  riastrad 	drm_atomic_state_put(state);
   1101  1.17  riastrad out_ctx:
   1102  1.17  riastrad 	drm_modeset_drop_locks(&ctx);
   1103  1.17  riastrad 	drm_modeset_acquire_fini(&ctx);
   1104  1.17  riastrad 
   1105  1.17  riastrad 	return ret;
   1106  1.17  riastrad 
   1107  1.17  riastrad backoff:
   1108  1.17  riastrad 	drm_atomic_state_clear(state);
   1109  1.17  riastrad 	drm_modeset_backoff(&ctx);
   1110  1.17  riastrad 	goto retry;
   1111   1.1  riastrad }
   1112   1.1  riastrad 
   1113   1.5  riastrad /**
   1114  1.17  riastrad  * drm_fb_helper_setcmap - implementation for &fb_ops.fb_setcmap
   1115   1.5  riastrad  * @cmap: cmap to set
   1116   1.5  riastrad  * @info: fbdev registered by the helper
   1117   1.5  riastrad  */
   1118   1.1  riastrad int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
   1119   1.1  riastrad {
   1120   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1121   1.5  riastrad 	struct drm_device *dev = fb_helper->dev;
   1122  1.17  riastrad 	int ret;
   1123   1.1  riastrad 
   1124   1.9  riastrad 	if (oops_in_progress)
   1125   1.9  riastrad 		return -EBUSY;
   1126   1.9  riastrad 
   1127  1.17  riastrad 	mutex_lock(&fb_helper->lock);
   1128  1.17  riastrad 
   1129  1.17  riastrad 	if (!drm_master_internal_acquire(dev)) {
   1130  1.17  riastrad 		ret = -EBUSY;
   1131  1.17  riastrad 		goto unlock;
   1132   1.5  riastrad 	}
   1133   1.5  riastrad 
   1134  1.17  riastrad 	mutex_lock(&fb_helper->client.modeset_mutex);
   1135  1.17  riastrad 	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
   1136  1.17  riastrad 		ret = setcmap_pseudo_palette(cmap, info);
   1137  1.17  riastrad 	else if (drm_drv_uses_atomic_modeset(fb_helper->dev))
   1138  1.17  riastrad 		ret = setcmap_atomic(cmap, info);
   1139  1.17  riastrad 	else
   1140  1.17  riastrad 		ret = setcmap_legacy(cmap, info);
   1141  1.17  riastrad 	mutex_unlock(&fb_helper->client.modeset_mutex);
   1142  1.17  riastrad 
   1143  1.17  riastrad 	drm_master_internal_release(dev);
   1144  1.17  riastrad unlock:
   1145  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
   1146  1.17  riastrad 
   1147  1.17  riastrad 	return ret;
   1148   1.1  riastrad }
   1149   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_setcmap);
   1150   1.1  riastrad 
   1151   1.5  riastrad /**
   1152  1.17  riastrad  * drm_fb_helper_ioctl - legacy ioctl implementation
   1153   1.5  riastrad  * @info: fbdev registered by the helper
   1154  1.17  riastrad  * @cmd: ioctl command
   1155  1.17  riastrad  * @arg: ioctl argument
   1156  1.17  riastrad  *
   1157  1.17  riastrad  * A helper to implement the standard fbdev ioctl. Only
   1158  1.17  riastrad  * FBIO_WAITFORVSYNC is implemented for now.
   1159   1.5  riastrad  */
   1160  1.17  riastrad int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
   1161  1.17  riastrad 			unsigned long arg)
   1162   1.1  riastrad {
   1163   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1164  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
   1165  1.17  riastrad 	struct drm_crtc *crtc;
   1166  1.17  riastrad 	int ret = 0;
   1167  1.17  riastrad 
   1168  1.17  riastrad 	mutex_lock(&fb_helper->lock);
   1169  1.17  riastrad 	if (!drm_master_internal_acquire(dev)) {
   1170  1.17  riastrad 		ret = -EBUSY;
   1171  1.17  riastrad 		goto unlock;
   1172  1.17  riastrad 	}
   1173   1.1  riastrad 
   1174  1.17  riastrad 	switch (cmd) {
   1175  1.17  riastrad 	case FBIO_WAITFORVSYNC:
   1176  1.17  riastrad 		/*
   1177  1.17  riastrad 		 * Only consider the first CRTC.
   1178  1.17  riastrad 		 *
   1179  1.17  riastrad 		 * This ioctl is supposed to take the CRTC number as
   1180  1.17  riastrad 		 * an argument, but in fbdev times, what that number
   1181  1.17  riastrad 		 * was supposed to be was quite unclear, different
   1182  1.17  riastrad 		 * drivers were passing that argument differently
   1183  1.17  riastrad 		 * (some by reference, some by value), and most of the
   1184  1.17  riastrad 		 * userspace applications were just hardcoding 0 as an
   1185  1.17  riastrad 		 * argument.
   1186  1.17  riastrad 		 *
   1187  1.17  riastrad 		 * The first CRTC should be the integrated panel on
   1188  1.17  riastrad 		 * most drivers, so this is the best choice we can
   1189  1.17  riastrad 		 * make. If we're not smart enough here, one should
   1190  1.17  riastrad 		 * just consider switch the userspace to KMS.
   1191  1.17  riastrad 		 */
   1192  1.17  riastrad 		crtc = fb_helper->client.modesets[0].crtc;
   1193   1.1  riastrad 
   1194  1.17  riastrad 		/*
   1195  1.17  riastrad 		 * Only wait for a vblank event if the CRTC is
   1196  1.17  riastrad 		 * enabled, otherwise just don't do anythintg,
   1197  1.17  riastrad 		 * not even report an error.
   1198  1.17  riastrad 		 */
   1199  1.17  riastrad 		ret = drm_crtc_vblank_get(crtc);
   1200  1.17  riastrad 		if (!ret) {
   1201  1.17  riastrad 			drm_crtc_wait_one_vblank(crtc);
   1202  1.17  riastrad 			drm_crtc_vblank_put(crtc);
   1203  1.17  riastrad 		}
   1204   1.1  riastrad 
   1205  1.17  riastrad 		ret = 0;
   1206   1.1  riastrad 		break;
   1207   1.1  riastrad 	default:
   1208  1.17  riastrad 		ret = -ENOTTY;
   1209   1.1  riastrad 	}
   1210   1.1  riastrad 
   1211  1.17  riastrad 	drm_master_internal_release(dev);
   1212  1.17  riastrad unlock:
   1213  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
   1214  1.17  riastrad 	return ret;
   1215  1.17  riastrad }
   1216  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_ioctl);
   1217  1.17  riastrad 
   1218  1.17  riastrad static bool drm_fb_pixel_format_equal(const struct fb_var_screeninfo *var_1,
   1219  1.17  riastrad 				      const struct fb_var_screeninfo *var_2)
   1220  1.17  riastrad {
   1221  1.17  riastrad 	return var_1->bits_per_pixel == var_2->bits_per_pixel &&
   1222  1.17  riastrad 	       var_1->grayscale == var_2->grayscale &&
   1223  1.17  riastrad 	       var_1->red.offset == var_2->red.offset &&
   1224  1.17  riastrad 	       var_1->red.length == var_2->red.length &&
   1225  1.17  riastrad 	       var_1->red.msb_right == var_2->red.msb_right &&
   1226  1.17  riastrad 	       var_1->green.offset == var_2->green.offset &&
   1227  1.17  riastrad 	       var_1->green.length == var_2->green.length &&
   1228  1.17  riastrad 	       var_1->green.msb_right == var_2->green.msb_right &&
   1229  1.17  riastrad 	       var_1->blue.offset == var_2->blue.offset &&
   1230  1.17  riastrad 	       var_1->blue.length == var_2->blue.length &&
   1231  1.17  riastrad 	       var_1->blue.msb_right == var_2->blue.msb_right &&
   1232  1.17  riastrad 	       var_1->transp.offset == var_2->transp.offset &&
   1233  1.17  riastrad 	       var_1->transp.length == var_2->transp.length &&
   1234  1.17  riastrad 	       var_1->transp.msb_right == var_2->transp.msb_right;
   1235  1.17  riastrad }
   1236  1.17  riastrad 
   1237  1.17  riastrad static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
   1238  1.17  riastrad 					 u8 depth)
   1239  1.17  riastrad {
   1240   1.1  riastrad 	switch (depth) {
   1241   1.1  riastrad 	case 8:
   1242   1.1  riastrad 		var->red.offset = 0;
   1243   1.1  riastrad 		var->green.offset = 0;
   1244   1.1  riastrad 		var->blue.offset = 0;
   1245  1.17  riastrad 		var->red.length = 8; /* 8bit DAC */
   1246   1.1  riastrad 		var->green.length = 8;
   1247   1.1  riastrad 		var->blue.length = 8;
   1248  1.17  riastrad 		var->transp.offset = 0;
   1249   1.1  riastrad 		var->transp.length = 0;
   1250   1.1  riastrad 		break;
   1251   1.1  riastrad 	case 15:
   1252   1.1  riastrad 		var->red.offset = 10;
   1253   1.1  riastrad 		var->green.offset = 5;
   1254   1.1  riastrad 		var->blue.offset = 0;
   1255   1.1  riastrad 		var->red.length = 5;
   1256   1.1  riastrad 		var->green.length = 5;
   1257   1.1  riastrad 		var->blue.length = 5;
   1258  1.17  riastrad 		var->transp.offset = 15;
   1259   1.1  riastrad 		var->transp.length = 1;
   1260   1.1  riastrad 		break;
   1261   1.1  riastrad 	case 16:
   1262   1.1  riastrad 		var->red.offset = 11;
   1263   1.1  riastrad 		var->green.offset = 5;
   1264   1.1  riastrad 		var->blue.offset = 0;
   1265   1.1  riastrad 		var->red.length = 5;
   1266   1.1  riastrad 		var->green.length = 6;
   1267   1.1  riastrad 		var->blue.length = 5;
   1268   1.1  riastrad 		var->transp.offset = 0;
   1269   1.1  riastrad 		break;
   1270   1.1  riastrad 	case 24:
   1271   1.1  riastrad 		var->red.offset = 16;
   1272   1.1  riastrad 		var->green.offset = 8;
   1273   1.1  riastrad 		var->blue.offset = 0;
   1274   1.1  riastrad 		var->red.length = 8;
   1275   1.1  riastrad 		var->green.length = 8;
   1276   1.1  riastrad 		var->blue.length = 8;
   1277  1.17  riastrad 		var->transp.offset = 0;
   1278   1.1  riastrad 		var->transp.length = 0;
   1279   1.1  riastrad 		break;
   1280   1.1  riastrad 	case 32:
   1281   1.1  riastrad 		var->red.offset = 16;
   1282   1.1  riastrad 		var->green.offset = 8;
   1283   1.1  riastrad 		var->blue.offset = 0;
   1284   1.1  riastrad 		var->red.length = 8;
   1285   1.1  riastrad 		var->green.length = 8;
   1286   1.1  riastrad 		var->blue.length = 8;
   1287  1.17  riastrad 		var->transp.offset = 24;
   1288   1.1  riastrad 		var->transp.length = 8;
   1289   1.1  riastrad 		break;
   1290   1.1  riastrad 	default:
   1291  1.17  riastrad 		break;
   1292  1.17  riastrad 	}
   1293  1.17  riastrad }
   1294  1.17  riastrad 
   1295  1.17  riastrad /**
   1296  1.17  riastrad  * drm_fb_helper_check_var - implementation for &fb_ops.fb_check_var
   1297  1.17  riastrad  * @var: screeninfo to check
   1298  1.17  riastrad  * @info: fbdev registered by the helper
   1299  1.17  riastrad  */
   1300  1.17  riastrad int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
   1301  1.17  riastrad 			    struct fb_info *info)
   1302  1.17  riastrad {
   1303  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1304  1.17  riastrad 	struct drm_framebuffer *fb = fb_helper->fb;
   1305  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
   1306  1.17  riastrad 
   1307  1.17  riastrad 	if (in_dbg_master())
   1308  1.17  riastrad 		return -EINVAL;
   1309  1.17  riastrad 
   1310  1.17  riastrad 	if (var->pixclock != 0) {
   1311  1.17  riastrad 		drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel clock, value of pixclock is ignored\n");
   1312  1.17  riastrad 		var->pixclock = 0;
   1313  1.17  riastrad 	}
   1314  1.17  riastrad 
   1315  1.17  riastrad 	if ((drm_format_info_block_width(fb->format, 0) > 1) ||
   1316  1.17  riastrad 	    (drm_format_info_block_height(fb->format, 0) > 1))
   1317  1.17  riastrad 		return -EINVAL;
   1318  1.17  riastrad 
   1319  1.17  riastrad 	/*
   1320  1.17  riastrad 	 * Changes struct fb_var_screeninfo are currently not pushed back
   1321  1.17  riastrad 	 * to KMS, hence fail if different settings are requested.
   1322  1.17  riastrad 	 */
   1323  1.17  riastrad 	if (var->bits_per_pixel > fb->format->cpp[0] * 8 ||
   1324  1.17  riastrad 	    var->xres > fb->width || var->yres > fb->height ||
   1325  1.17  riastrad 	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
   1326  1.17  riastrad 		drm_dbg_kms(dev, "fb requested width/height/bpp can't fit in current fb "
   1327  1.17  riastrad 			  "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
   1328  1.17  riastrad 			  var->xres, var->yres, var->bits_per_pixel,
   1329  1.17  riastrad 			  var->xres_virtual, var->yres_virtual,
   1330  1.17  riastrad 			  fb->width, fb->height, fb->format->cpp[0] * 8);
   1331  1.17  riastrad 		return -EINVAL;
   1332  1.17  riastrad 	}
   1333  1.17  riastrad 
   1334  1.17  riastrad 	/*
   1335  1.17  riastrad 	 * Workaround for SDL 1.2, which is known to be setting all pixel format
   1336  1.17  riastrad 	 * fields values to zero in some cases. We treat this situation as a
   1337  1.17  riastrad 	 * kind of "use some reasonable autodetected values".
   1338  1.17  riastrad 	 */
   1339  1.17  riastrad 	if (!var->red.offset     && !var->green.offset    &&
   1340  1.17  riastrad 	    !var->blue.offset    && !var->transp.offset   &&
   1341  1.17  riastrad 	    !var->red.length     && !var->green.length    &&
   1342  1.17  riastrad 	    !var->blue.length    && !var->transp.length   &&
   1343  1.17  riastrad 	    !var->red.msb_right  && !var->green.msb_right &&
   1344  1.17  riastrad 	    !var->blue.msb_right && !var->transp.msb_right) {
   1345  1.17  riastrad 		drm_fb_helper_fill_pixel_fmt(var, fb->format->depth);
   1346  1.17  riastrad 	}
   1347  1.17  riastrad 
   1348  1.17  riastrad 	/*
   1349  1.17  riastrad 	 * Likewise, bits_per_pixel should be rounded up to a supported value.
   1350  1.17  riastrad 	 */
   1351  1.17  riastrad 	var->bits_per_pixel = fb->format->cpp[0] * 8;
   1352  1.17  riastrad 
   1353  1.17  riastrad 	/*
   1354  1.17  riastrad 	 * drm fbdev emulation doesn't support changing the pixel format at all,
   1355  1.17  riastrad 	 * so reject all pixel format changing requests.
   1356  1.17  riastrad 	 */
   1357  1.17  riastrad 	if (!drm_fb_pixel_format_equal(var, &info->var)) {
   1358  1.17  riastrad 		drm_dbg_kms(dev, "fbdev emulation doesn't support changing the pixel format\n");
   1359   1.1  riastrad 		return -EINVAL;
   1360   1.1  riastrad 	}
   1361  1.17  riastrad 
   1362   1.1  riastrad 	return 0;
   1363   1.1  riastrad }
   1364   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_check_var);
   1365   1.1  riastrad 
   1366   1.5  riastrad /**
   1367  1.17  riastrad  * drm_fb_helper_set_par - implementation for &fb_ops.fb_set_par
   1368   1.5  riastrad  * @info: fbdev registered by the helper
   1369   1.5  riastrad  *
   1370   1.5  riastrad  * This will let fbcon do the mode init and is called at initialization time by
   1371   1.5  riastrad  * the fbdev core when registering the driver, and later on through the hotplug
   1372   1.5  riastrad  * callback.
   1373   1.5  riastrad  */
   1374   1.2  riastrad int drm_fb_helper_set_par(struct fb_info *info)
   1375   1.2  riastrad {
   1376   1.2  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1377   1.2  riastrad 	struct fb_var_screeninfo *var = &info->var;
   1378   1.2  riastrad 
   1379   1.9  riastrad 	if (oops_in_progress)
   1380   1.9  riastrad 		return -EBUSY;
   1381   1.9  riastrad 
   1382   1.2  riastrad 	if (var->pixclock != 0) {
   1383  1.17  riastrad 		drm_err(fb_helper->dev, "PIXEL CLOCK SET\n");
   1384   1.2  riastrad 		return -EINVAL;
   1385   1.2  riastrad 	}
   1386   1.2  riastrad 
   1387   1.9  riastrad 	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
   1388   1.9  riastrad 
   1389   1.9  riastrad 	return 0;
   1390   1.2  riastrad }
   1391   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_set_par);
   1392   1.9  riastrad 
   1393  1.17  riastrad static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
   1394  1.17  riastrad {
   1395  1.17  riastrad 	struct drm_mode_set *mode_set;
   1396  1.17  riastrad 
   1397  1.17  riastrad 	mutex_lock(&fb_helper->client.modeset_mutex);
   1398  1.17  riastrad 	drm_client_for_each_modeset(mode_set, &fb_helper->client) {
   1399  1.17  riastrad 		mode_set->x = x;
   1400  1.17  riastrad 		mode_set->y = y;
   1401  1.17  riastrad 	}
   1402  1.17  riastrad 	mutex_unlock(&fb_helper->client.modeset_mutex);
   1403  1.17  riastrad }
   1404  1.17  riastrad 
   1405   1.9  riastrad static int pan_display_atomic(struct fb_var_screeninfo *var,
   1406   1.9  riastrad 			      struct fb_info *info)
   1407   1.9  riastrad {
   1408   1.9  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1409  1.17  riastrad 	int ret;
   1410   1.9  riastrad 
   1411  1.17  riastrad 	pan_set(fb_helper, var->xoffset, var->yoffset);
   1412   1.9  riastrad 
   1413  1.17  riastrad 	ret = drm_client_modeset_commit_force(&fb_helper->client);
   1414  1.17  riastrad 	if (!ret) {
   1415  1.17  riastrad 		info->var.xoffset = var->xoffset;
   1416  1.17  riastrad 		info->var.yoffset = var->yoffset;
   1417  1.17  riastrad 	} else
   1418  1.17  riastrad 		pan_set(fb_helper, info->var.xoffset, info->var.yoffset);
   1419   1.9  riastrad 
   1420  1.17  riastrad 	return ret;
   1421  1.17  riastrad }
   1422   1.9  riastrad 
   1423  1.17  riastrad static int pan_display_legacy(struct fb_var_screeninfo *var,
   1424  1.17  riastrad 			      struct fb_info *info)
   1425  1.17  riastrad {
   1426  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1427  1.17  riastrad 	struct drm_client_dev *client = &fb_helper->client;
   1428  1.17  riastrad 	struct drm_mode_set *modeset;
   1429  1.17  riastrad 	int ret = 0;
   1430   1.9  riastrad 
   1431  1.17  riastrad 	mutex_lock(&client->modeset_mutex);
   1432  1.17  riastrad 	drm_modeset_lock_all(fb_helper->dev);
   1433  1.17  riastrad 	drm_client_for_each_modeset(modeset, client) {
   1434  1.17  riastrad 		modeset->x = var->xoffset;
   1435  1.17  riastrad 		modeset->y = var->yoffset;
   1436   1.9  riastrad 
   1437  1.17  riastrad 		if (modeset->num_connectors) {
   1438  1.17  riastrad 			ret = drm_mode_set_config_internal(modeset);
   1439  1.17  riastrad 			if (!ret) {
   1440  1.17  riastrad 				info->var.xoffset = var->xoffset;
   1441  1.17  riastrad 				info->var.yoffset = var->yoffset;
   1442  1.17  riastrad 			}
   1443  1.17  riastrad 		}
   1444  1.17  riastrad 	}
   1445  1.17  riastrad 	drm_modeset_unlock_all(fb_helper->dev);
   1446  1.17  riastrad 	mutex_unlock(&client->modeset_mutex);
   1447   1.9  riastrad 
   1448   1.9  riastrad 	return ret;
   1449   1.5  riastrad }
   1450   1.5  riastrad 
   1451   1.5  riastrad /**
   1452  1.17  riastrad  * drm_fb_helper_pan_display - implementation for &fb_ops.fb_pan_display
   1453   1.5  riastrad  * @var: updated screen information
   1454   1.5  riastrad  * @info: fbdev registered by the helper
   1455   1.5  riastrad  */
   1456   1.1  riastrad int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
   1457   1.1  riastrad 			      struct fb_info *info)
   1458   1.1  riastrad {
   1459   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   1460   1.1  riastrad 	struct drm_device *dev = fb_helper->dev;
   1461  1.17  riastrad 	int ret;
   1462   1.1  riastrad 
   1463   1.9  riastrad 	if (oops_in_progress)
   1464   1.9  riastrad 		return -EBUSY;
   1465   1.9  riastrad 
   1466  1.17  riastrad 	mutex_lock(&fb_helper->lock);
   1467  1.17  riastrad 	if (!drm_master_internal_acquire(dev)) {
   1468  1.17  riastrad 		ret = -EBUSY;
   1469  1.17  riastrad 		goto unlock;
   1470   1.5  riastrad 	}
   1471   1.5  riastrad 
   1472  1.17  riastrad 	if (drm_drv_uses_atomic_modeset(dev))
   1473   1.9  riastrad 		ret = pan_display_atomic(var, info);
   1474  1.17  riastrad 	else
   1475  1.17  riastrad 		ret = pan_display_legacy(var, info);
   1476   1.9  riastrad 
   1477  1.17  riastrad 	drm_master_internal_release(dev);
   1478  1.17  riastrad unlock:
   1479  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
   1480   1.1  riastrad 
   1481   1.1  riastrad 	return ret;
   1482   1.1  riastrad }
   1483   1.1  riastrad EXPORT_SYMBOL(drm_fb_helper_pan_display);
   1484  1.24  riastrad 
   1485   1.2  riastrad #endif
   1486   1.1  riastrad 
   1487   1.5  riastrad /*
   1488   1.5  riastrad  * Allocates the backing storage and sets up the fbdev info structure through
   1489  1.17  riastrad  * the ->fb_probe callback.
   1490   1.5  riastrad  */
   1491   1.5  riastrad static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
   1492   1.5  riastrad 					 int preferred_bpp)
   1493   1.1  riastrad {
   1494  1.17  riastrad 	struct drm_client_dev *client = &fb_helper->client;
   1495  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
   1496   1.5  riastrad 	int ret = 0;
   1497   1.1  riastrad 	int crtc_count = 0;
   1498  1.17  riastrad 	struct drm_connector_list_iter conn_iter;
   1499   1.1  riastrad 	struct drm_fb_helper_surface_size sizes;
   1500  1.17  riastrad 	struct drm_connector *connector;
   1501  1.17  riastrad 	struct drm_mode_set *mode_set;
   1502  1.17  riastrad 	int best_depth = 0;
   1503   1.1  riastrad 
   1504   1.1  riastrad 	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
   1505   1.1  riastrad 	sizes.surface_depth = 24;
   1506   1.1  riastrad 	sizes.surface_bpp = 32;
   1507  1.17  riastrad 	sizes.fb_width = (u32)-1;
   1508  1.17  riastrad 	sizes.fb_height = (u32)-1;
   1509   1.1  riastrad 
   1510  1.17  riastrad 	/*
   1511  1.17  riastrad 	 * If driver picks 8 or 16 by default use that for both depth/bpp
   1512  1.17  riastrad 	 * to begin with
   1513  1.17  riastrad 	 */
   1514   1.1  riastrad 	if (preferred_bpp != sizes.surface_bpp)
   1515   1.1  riastrad 		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
   1516   1.1  riastrad 
   1517  1.17  riastrad 	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
   1518  1.17  riastrad 	drm_client_for_each_connector_iter(connector, &conn_iter) {
   1519   1.1  riastrad 		struct drm_cmdline_mode *cmdline_mode;
   1520   1.1  riastrad 
   1521  1.17  riastrad 		cmdline_mode = &connector->cmdline_mode;
   1522   1.1  riastrad 
   1523   1.1  riastrad 		if (cmdline_mode->bpp_specified) {
   1524   1.1  riastrad 			switch (cmdline_mode->bpp) {
   1525   1.1  riastrad 			case 8:
   1526   1.1  riastrad 				sizes.surface_depth = sizes.surface_bpp = 8;
   1527   1.1  riastrad 				break;
   1528   1.1  riastrad 			case 15:
   1529   1.1  riastrad 				sizes.surface_depth = 15;
   1530   1.1  riastrad 				sizes.surface_bpp = 16;
   1531   1.1  riastrad 				break;
   1532   1.1  riastrad 			case 16:
   1533   1.1  riastrad 				sizes.surface_depth = sizes.surface_bpp = 16;
   1534   1.1  riastrad 				break;
   1535   1.1  riastrad 			case 24:
   1536   1.1  riastrad 				sizes.surface_depth = sizes.surface_bpp = 24;
   1537   1.1  riastrad 				break;
   1538   1.1  riastrad 			case 32:
   1539   1.1  riastrad 				sizes.surface_depth = 24;
   1540   1.1  riastrad 				sizes.surface_bpp = 32;
   1541   1.1  riastrad 				break;
   1542   1.1  riastrad 			}
   1543   1.1  riastrad 			break;
   1544   1.1  riastrad 		}
   1545   1.1  riastrad 	}
   1546  1.17  riastrad 	drm_connector_list_iter_end(&conn_iter);
   1547  1.17  riastrad 
   1548  1.17  riastrad 	/*
   1549  1.17  riastrad 	 * If we run into a situation where, for example, the primary plane
   1550  1.17  riastrad 	 * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth
   1551  1.17  riastrad 	 * 16) we need to scale down the depth of the sizes we request.
   1552  1.17  riastrad 	 */
   1553  1.17  riastrad 	mutex_lock(&client->modeset_mutex);
   1554  1.17  riastrad 	drm_client_for_each_modeset(mode_set, client) {
   1555  1.17  riastrad 		struct drm_crtc *crtc = mode_set->crtc;
   1556  1.17  riastrad 		struct drm_plane *plane = crtc->primary;
   1557  1.17  riastrad 		int j;
   1558  1.17  riastrad 
   1559  1.17  riastrad 		drm_dbg_kms(dev, "test CRTC %u primary plane\n", drm_crtc_index(crtc));
   1560  1.17  riastrad 
   1561  1.17  riastrad 		for (j = 0; j < plane->format_count; j++) {
   1562  1.17  riastrad 			const struct drm_format_info *fmt;
   1563  1.17  riastrad 
   1564  1.17  riastrad 			fmt = drm_format_info(plane->format_types[j]);
   1565  1.17  riastrad 
   1566  1.17  riastrad 			/*
   1567  1.17  riastrad 			 * Do not consider YUV or other complicated formats
   1568  1.17  riastrad 			 * for framebuffers. This means only legacy formats
   1569  1.17  riastrad 			 * are supported (fmt->depth is a legacy field) but
   1570  1.17  riastrad 			 * the framebuffer emulation can only deal with such
   1571  1.17  riastrad 			 * formats, specifically RGB/BGA formats.
   1572  1.17  riastrad 			 */
   1573  1.17  riastrad 			if (fmt->depth == 0)
   1574  1.17  riastrad 				continue;
   1575  1.17  riastrad 
   1576  1.17  riastrad 			/* We found a perfect fit, great */
   1577  1.17  riastrad 			if (fmt->depth == sizes.surface_depth) {
   1578  1.17  riastrad 				best_depth = fmt->depth;
   1579  1.17  riastrad 				break;
   1580  1.17  riastrad 			}
   1581  1.17  riastrad 
   1582  1.17  riastrad 			/* Skip depths above what we're looking for */
   1583  1.17  riastrad 			if (fmt->depth > sizes.surface_depth)
   1584  1.17  riastrad 				continue;
   1585  1.17  riastrad 
   1586  1.17  riastrad 			/* Best depth found so far */
   1587  1.17  riastrad 			if (fmt->depth > best_depth)
   1588  1.17  riastrad 				best_depth = fmt->depth;
   1589  1.17  riastrad 		}
   1590  1.17  riastrad 	}
   1591  1.17  riastrad 	if (sizes.surface_depth != best_depth && best_depth) {
   1592  1.17  riastrad 		drm_info(dev, "requested bpp %d, scaled depth down to %d",
   1593  1.17  riastrad 			 sizes.surface_bpp, best_depth);
   1594  1.17  riastrad 		sizes.surface_depth = best_depth;
   1595  1.17  riastrad 	}
   1596   1.1  riastrad 
   1597  1.17  riastrad 	/* first up get a count of crtcs now in use and new min/maxes width/heights */
   1598   1.1  riastrad 	crtc_count = 0;
   1599  1.17  riastrad 	drm_client_for_each_modeset(mode_set, client) {
   1600   1.1  riastrad 		struct drm_display_mode *desired_mode;
   1601   1.9  riastrad 		int x, y, j;
   1602   1.9  riastrad 		/* in case of tile group, are we the last tile vert or horiz?
   1603   1.9  riastrad 		 * If no tile group you are always the last one both vertically
   1604   1.9  riastrad 		 * and horizontally
   1605   1.9  riastrad 		 */
   1606   1.9  riastrad 		bool lastv = true, lasth = true;
   1607   1.9  riastrad 
   1608  1.17  riastrad 		desired_mode = mode_set->mode;
   1609   1.9  riastrad 
   1610   1.9  riastrad 		if (!desired_mode)
   1611   1.9  riastrad 			continue;
   1612   1.9  riastrad 
   1613   1.9  riastrad 		crtc_count++;
   1614   1.9  riastrad 
   1615  1.17  riastrad 		x = mode_set->x;
   1616  1.17  riastrad 		y = mode_set->y;
   1617   1.9  riastrad 
   1618   1.9  riastrad 		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
   1619   1.9  riastrad 		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
   1620   1.9  riastrad 
   1621   1.9  riastrad 		for (j = 0; j < mode_set->num_connectors; j++) {
   1622   1.9  riastrad 			struct drm_connector *connector = mode_set->connectors[j];
   1623  1.17  riastrad 
   1624  1.17  riastrad 			if (connector->has_tile &&
   1625  1.17  riastrad 			    desired_mode->hdisplay == connector->tile_h_size &&
   1626  1.17  riastrad 			    desired_mode->vdisplay == connector->tile_v_size) {
   1627   1.9  riastrad 				lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
   1628   1.9  riastrad 				lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
   1629   1.9  riastrad 				/* cloning to multiple tiles is just crazy-talk, so: */
   1630   1.9  riastrad 				break;
   1631   1.9  riastrad 			}
   1632   1.1  riastrad 		}
   1633   1.9  riastrad 
   1634   1.9  riastrad 		if (lasth)
   1635   1.9  riastrad 			sizes.fb_width  = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
   1636   1.9  riastrad 		if (lastv)
   1637   1.9  riastrad 			sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
   1638   1.1  riastrad 	}
   1639  1.17  riastrad 	mutex_unlock(&client->modeset_mutex);
   1640   1.1  riastrad 
   1641   1.1  riastrad 	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
   1642  1.17  riastrad 		drm_info(dev, "Cannot find any crtc or sizes\n");
   1643  1.17  riastrad 
   1644  1.17  riastrad 		/* First time: disable all crtc's.. */
   1645  1.17  riastrad 		if (!fb_helper->deferred_setup)
   1646  1.17  riastrad 			drm_client_modeset_commit(client);
   1647  1.17  riastrad 		return -EAGAIN;
   1648   1.1  riastrad 	}
   1649   1.1  riastrad 
   1650  1.17  riastrad 	/* Handle our overallocation */
   1651  1.17  riastrad 	sizes.surface_height *= drm_fbdev_overalloc;
   1652  1.17  riastrad 	sizes.surface_height /= 100;
   1653  1.17  riastrad 
   1654   1.1  riastrad 	/* push down into drivers */
   1655   1.5  riastrad 	ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
   1656   1.5  riastrad 	if (ret < 0)
   1657   1.5  riastrad 		return ret;
   1658   1.1  riastrad 
   1659  1.17  riastrad 	strcpy(fb_helper->fb->comm, "[fbcon]");
   1660   1.1  riastrad 	return 0;
   1661   1.1  riastrad }
   1662   1.1  riastrad 
   1663   1.2  riastrad #ifndef __NetBSD__		/* XXX fb info */
   1664  1.17  riastrad static void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
   1665  1.17  riastrad 				   uint32_t depth)
   1666   1.1  riastrad {
   1667   1.1  riastrad 	info->fix.type = FB_TYPE_PACKED_PIXELS;
   1668   1.1  riastrad 	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
   1669   1.1  riastrad 		FB_VISUAL_TRUECOLOR;
   1670   1.1  riastrad 	info->fix.mmio_start = 0;
   1671   1.1  riastrad 	info->fix.mmio_len = 0;
   1672   1.1  riastrad 	info->fix.type_aux = 0;
   1673   1.1  riastrad 	info->fix.xpanstep = 1; /* doing it in hw */
   1674   1.1  riastrad 	info->fix.ypanstep = 1; /* doing it in hw */
   1675   1.1  riastrad 	info->fix.ywrapstep = 0;
   1676   1.1  riastrad 	info->fix.accel = FB_ACCEL_NONE;
   1677   1.1  riastrad 
   1678   1.1  riastrad 	info->fix.line_length = pitch;
   1679   1.1  riastrad }
   1680   1.1  riastrad 
   1681  1.17  riastrad static void drm_fb_helper_fill_var(struct fb_info *info,
   1682  1.17  riastrad 				   struct drm_fb_helper *fb_helper,
   1683  1.17  riastrad 				   uint32_t fb_width, uint32_t fb_height)
   1684   1.1  riastrad {
   1685   1.1  riastrad 	struct drm_framebuffer *fb = fb_helper->fb;
   1686  1.17  riastrad 
   1687  1.17  riastrad 	WARN_ON((drm_format_info_block_width(fb->format, 0) > 1) ||
   1688  1.17  riastrad 		(drm_format_info_block_height(fb->format, 0) > 1));
   1689   1.1  riastrad 	info->pseudo_palette = fb_helper->pseudo_palette;
   1690   1.1  riastrad 	info->var.xres_virtual = fb->width;
   1691   1.1  riastrad 	info->var.yres_virtual = fb->height;
   1692  1.17  riastrad 	info->var.bits_per_pixel = fb->format->cpp[0] * 8;
   1693   1.1  riastrad 	info->var.accel_flags = FB_ACCELF_TEXT;
   1694   1.1  riastrad 	info->var.xoffset = 0;
   1695   1.1  riastrad 	info->var.yoffset = 0;
   1696   1.1  riastrad 	info->var.activate = FB_ACTIVATE_NOW;
   1697   1.1  riastrad 
   1698  1.17  riastrad 	drm_fb_helper_fill_pixel_fmt(&info->var, fb->format->depth);
   1699   1.1  riastrad 
   1700   1.1  riastrad 	info->var.xres = fb_width;
   1701   1.1  riastrad 	info->var.yres = fb_height;
   1702   1.1  riastrad }
   1703   1.1  riastrad 
   1704  1.17  riastrad /**
   1705  1.17  riastrad  * drm_fb_helper_fill_info - initializes fbdev information
   1706  1.17  riastrad  * @info: fbdev instance to set up
   1707  1.17  riastrad  * @fb_helper: fb helper instance to use as template
   1708  1.17  riastrad  * @sizes: describes fbdev size and scanout surface size
   1709  1.17  riastrad  *
   1710  1.17  riastrad  * Sets up the variable and fixed fbdev metainformation from the given fb helper
   1711  1.17  riastrad  * instance and the drm framebuffer allocated in &drm_fb_helper.fb.
   1712  1.17  riastrad  *
   1713  1.17  riastrad  * Drivers should call this (or their equivalent setup code) from their
   1714  1.17  riastrad  * &drm_fb_helper_funcs.fb_probe callback after having allocated the fbdev
   1715  1.17  riastrad  * backing storage framebuffer.
   1716  1.17  riastrad  */
   1717  1.17  riastrad void drm_fb_helper_fill_info(struct fb_info *info,
   1718  1.17  riastrad 			     struct drm_fb_helper *fb_helper,
   1719  1.17  riastrad 			     struct drm_fb_helper_surface_size *sizes)
   1720   1.1  riastrad {
   1721  1.17  riastrad 	struct drm_framebuffer *fb = fb_helper->fb;
   1722  1.17  riastrad 
   1723  1.17  riastrad 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
   1724  1.17  riastrad 	drm_fb_helper_fill_var(info, fb_helper,
   1725  1.17  riastrad 			       sizes->fb_width, sizes->fb_height);
   1726   1.1  riastrad 
   1727  1.17  riastrad 	info->par = fb_helper;
   1728  1.17  riastrad 	snprintf(info->fix.id, sizeof(info->fix.id), "%sdrmfb",
   1729  1.17  riastrad 		 fb_helper->dev->driver->name);
   1730   1.1  riastrad 
   1731   1.1  riastrad }
   1732  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_fill_info);
   1733  1.22  riastrad #endif
   1734   1.1  riastrad 
   1735  1.17  riastrad /*
   1736  1.17  riastrad  * This is a continuation of drm_setup_crtcs() that sets up anything related
   1737  1.17  riastrad  * to the framebuffer. During initialization, drm_setup_crtcs() is called before
   1738  1.17  riastrad  * the framebuffer has been allocated (fb_helper->fb and fb_helper->fbdev).
   1739  1.17  riastrad  * So, any setup that touches those fields needs to be done here instead of in
   1740  1.17  riastrad  * drm_setup_crtcs().
   1741  1.17  riastrad  */
   1742  1.17  riastrad static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
   1743   1.1  riastrad {
   1744  1.17  riastrad 	struct drm_client_dev *client = &fb_helper->client;
   1745  1.22  riastrad #ifndef __NetBSD__		/* XXX fb info */
   1746  1.17  riastrad 	struct drm_connector_list_iter conn_iter;
   1747  1.17  riastrad 	struct fb_info *info = fb_helper->fbdev;
   1748  1.22  riastrad 	struct drm_connector *connector;
   1749  1.17  riastrad #endif
   1750  1.17  riastrad 	unsigned int rotation, sw_rotations = 0;
   1751  1.17  riastrad 	struct drm_mode_set *modeset;
   1752   1.1  riastrad 
   1753  1.17  riastrad 	mutex_lock(&client->modeset_mutex);
   1754  1.17  riastrad 	drm_client_for_each_modeset(modeset, client) {
   1755  1.17  riastrad 		if (!modeset->num_connectors)
   1756   1.1  riastrad 			continue;
   1757  1.17  riastrad 
   1758  1.17  riastrad 		modeset->fb = fb_helper->fb;
   1759  1.17  riastrad 
   1760  1.17  riastrad 		if (drm_client_rotation(modeset, &rotation))
   1761  1.17  riastrad 			/* Rotating in hardware, fbcon should not rotate */
   1762  1.17  riastrad 			sw_rotations |= DRM_MODE_ROTATE_0;
   1763  1.17  riastrad 		else
   1764  1.17  riastrad 			sw_rotations |= rotation;
   1765  1.17  riastrad 	}
   1766  1.17  riastrad 	mutex_unlock(&client->modeset_mutex);
   1767  1.17  riastrad 
   1768  1.20  riastrad #ifndef __NetBSD__		/* XXX fb info */
   1769  1.17  riastrad 	drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
   1770  1.17  riastrad 	drm_client_for_each_connector_iter(connector, &conn_iter) {
   1771  1.17  riastrad 
   1772  1.17  riastrad 		/* use first connected connector for the physical dimensions */
   1773  1.17  riastrad 		if (connector->status == connector_status_connected) {
   1774  1.17  riastrad 			info->var.width = connector->display_info.width_mm;
   1775  1.17  riastrad 			info->var.height = connector->display_info.height_mm;
   1776  1.17  riastrad 			break;
   1777  1.17  riastrad 		}
   1778  1.17  riastrad 	}
   1779  1.17  riastrad 	drm_connector_list_iter_end(&conn_iter);
   1780  1.17  riastrad 
   1781  1.17  riastrad 	switch (sw_rotations) {
   1782  1.17  riastrad 	case DRM_MODE_ROTATE_0:
   1783  1.17  riastrad 		info->fbcon_rotate_hint = FB_ROTATE_UR;
   1784  1.17  riastrad 		break;
   1785  1.17  riastrad 	case DRM_MODE_ROTATE_90:
   1786  1.17  riastrad 		info->fbcon_rotate_hint = FB_ROTATE_CCW;
   1787  1.17  riastrad 		break;
   1788  1.17  riastrad 	case DRM_MODE_ROTATE_180:
   1789  1.17  riastrad 		info->fbcon_rotate_hint = FB_ROTATE_UD;
   1790  1.17  riastrad 		break;
   1791  1.17  riastrad 	case DRM_MODE_ROTATE_270:
   1792  1.17  riastrad 		info->fbcon_rotate_hint = FB_ROTATE_CW;
   1793  1.17  riastrad 		break;
   1794  1.17  riastrad 	default:
   1795  1.17  riastrad 		/*
   1796  1.17  riastrad 		 * Multiple bits are set / multiple rotations requested
   1797  1.17  riastrad 		 * fbcon cannot handle separate rotation settings per
   1798  1.17  riastrad 		 * output, so fallback to unrotated.
   1799  1.17  riastrad 		 */
   1800  1.17  riastrad 		info->fbcon_rotate_hint = FB_ROTATE_UR;
   1801   1.1  riastrad 	}
   1802  1.20  riastrad #endif
   1803   1.1  riastrad }
   1804   1.1  riastrad 
   1805  1.17  riastrad /* Note: Drops fb_helper->lock before returning. */
   1806  1.17  riastrad static int
   1807  1.17  riastrad __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
   1808  1.17  riastrad 					  int bpp_sel)
   1809   1.1  riastrad {
   1810  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
   1811  1.20  riastrad #ifndef __NetBSD__		/* XXX fb info */
   1812  1.17  riastrad 	struct fb_info *info;
   1813  1.20  riastrad #endif
   1814  1.17  riastrad 	unsigned int width, height;
   1815  1.17  riastrad 	int ret;
   1816   1.1  riastrad 
   1817  1.17  riastrad 	width = dev->mode_config.max_width;
   1818  1.17  riastrad 	height = dev->mode_config.max_height;
   1819   1.1  riastrad 
   1820  1.17  riastrad 	drm_client_modeset_probe(&fb_helper->client, width, height);
   1821  1.17  riastrad 	ret = drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
   1822  1.17  riastrad 	if (ret < 0) {
   1823  1.17  riastrad 		if (ret == -EAGAIN) {
   1824  1.17  riastrad 			fb_helper->preferred_bpp = bpp_sel;
   1825  1.17  riastrad 			fb_helper->deferred_setup = true;
   1826  1.17  riastrad 			ret = 0;
   1827  1.17  riastrad 		}
   1828  1.17  riastrad 		mutex_unlock(&fb_helper->lock);
   1829   1.1  riastrad 
   1830  1.17  riastrad 		return ret;
   1831  1.17  riastrad 	}
   1832  1.17  riastrad 	drm_setup_crtcs_fb(fb_helper);
   1833   1.1  riastrad 
   1834  1.17  riastrad 	fb_helper->deferred_setup = false;
   1835   1.1  riastrad 
   1836  1.21  riastrad #ifndef __NetBSD__		/* XXX fb info */
   1837  1.17  riastrad 	info = fb_helper->fbdev;
   1838  1.17  riastrad 	info->var.pixclock = 0;
   1839  1.17  riastrad 	/* Shamelessly allow physical address leaking to userspace */
   1840  1.17  riastrad #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
   1841  1.17  riastrad 	if (!drm_leak_fbdev_smem)
   1842  1.17  riastrad #endif
   1843  1.17  riastrad 		/* don't leak any physical addresses to userspace */
   1844  1.17  riastrad 		info->flags |= FBINFO_HIDE_SMEM_START;
   1845  1.17  riastrad #endif
   1846   1.1  riastrad 
   1847  1.17  riastrad 	/* Need to drop locks to avoid recursive deadlock in
   1848  1.17  riastrad 	 * register_framebuffer. This is ok because the only thing left to do is
   1849  1.17  riastrad 	 * register the fbdev emulation instance in kernel_fb_helper_list. */
   1850  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
   1851   1.1  riastrad 
   1852  1.21  riastrad #ifndef __NetBSD__		/* XXX fb info */
   1853  1.17  riastrad 	ret = register_framebuffer(info);
   1854  1.17  riastrad 	if (ret < 0)
   1855  1.17  riastrad 		return ret;
   1856   1.5  riastrad 
   1857  1.17  riastrad 	dev_info(dev->dev, "fb%d: %s frame buffer device\n",
   1858  1.17  riastrad 		 info->node, info->fix.id);
   1859  1.20  riastrad #endif
   1860   1.1  riastrad 
   1861  1.17  riastrad 	mutex_lock(&kernel_fb_helper_lock);
   1862  1.17  riastrad 	if (list_empty(&kernel_fb_helper_list))
   1863  1.17  riastrad 		register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
   1864   1.1  riastrad 
   1865  1.17  riastrad 	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
   1866  1.17  riastrad 	mutex_unlock(&kernel_fb_helper_lock);
   1867   1.1  riastrad 
   1868  1.17  riastrad 	return 0;
   1869   1.1  riastrad }
   1870   1.1  riastrad 
   1871  1.17  riastrad /**
   1872  1.17  riastrad  * drm_fb_helper_initial_config - setup a sane initial connector configuration
   1873  1.17  riastrad  * @fb_helper: fb_helper device struct
   1874  1.17  riastrad  * @bpp_sel: bpp value to use for the framebuffer configuration
   1875  1.17  riastrad  *
   1876  1.17  riastrad  * Scans the CRTCs and connectors and tries to put together an initial setup.
   1877  1.17  riastrad  * At the moment, this is a cloned configuration across all heads with
   1878  1.17  riastrad  * a new framebuffer object as the backing store.
   1879  1.17  riastrad  *
   1880  1.17  riastrad  * Note that this also registers the fbdev and so allows userspace to call into
   1881  1.17  riastrad  * the driver through the fbdev interfaces.
   1882  1.17  riastrad  *
   1883  1.17  riastrad  * This function will call down into the &drm_fb_helper_funcs.fb_probe callback
   1884  1.17  riastrad  * to let the driver allocate and initialize the fbdev info structure and the
   1885  1.17  riastrad  * drm framebuffer used to back the fbdev. drm_fb_helper_fill_info() is provided
   1886  1.17  riastrad  * as a helper to setup simple default values for the fbdev info structure.
   1887  1.17  riastrad  *
   1888  1.17  riastrad  * HANG DEBUGGING:
   1889  1.17  riastrad  *
   1890  1.17  riastrad  * When you have fbcon support built-in or already loaded, this function will do
   1891  1.17  riastrad  * a full modeset to setup the fbdev console. Due to locking misdesign in the
   1892  1.17  riastrad  * VT/fbdev subsystem that entire modeset sequence has to be done while holding
   1893  1.17  riastrad  * console_lock. Until console_unlock is called no dmesg lines will be sent out
   1894  1.17  riastrad  * to consoles, not even serial console. This means when your driver crashes,
   1895  1.17  riastrad  * you will see absolutely nothing else but a system stuck in this function,
   1896  1.17  riastrad  * with no further output. Any kind of printk() you place within your own driver
   1897  1.17  riastrad  * or in the drm core modeset code will also never show up.
   1898  1.17  riastrad  *
   1899  1.17  riastrad  * Standard debug practice is to run the fbcon setup without taking the
   1900  1.17  riastrad  * console_lock as a hack, to be able to see backtraces and crashes on the
   1901  1.17  riastrad  * serial line. This can be done by setting the fb.lockless_register_fb=1 kernel
   1902  1.17  riastrad  * cmdline option.
   1903  1.17  riastrad  *
   1904  1.17  riastrad  * The other option is to just disable fbdev emulation since very likely the
   1905  1.17  riastrad  * first modeset from userspace will crash in the same way, and is even easier
   1906  1.17  riastrad  * to debug. This can be done by setting the drm_kms_helper.fbdev_emulation=0
   1907  1.17  riastrad  * kernel cmdline option.
   1908  1.17  riastrad  *
   1909  1.17  riastrad  * RETURNS:
   1910  1.17  riastrad  * Zero if everything went ok, nonzero otherwise.
   1911  1.17  riastrad  */
   1912  1.17  riastrad int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
   1913   1.1  riastrad {
   1914  1.17  riastrad 	int ret;
   1915   1.1  riastrad 
   1916  1.17  riastrad 	if (!drm_fbdev_emulation)
   1917  1.17  riastrad 		return 0;
   1918   1.1  riastrad 
   1919  1.17  riastrad 	mutex_lock(&fb_helper->lock);
   1920  1.17  riastrad 	ret = __drm_fb_helper_initial_config_and_unlock(fb_helper, bpp_sel);
   1921   1.1  riastrad 
   1922  1.17  riastrad 	return ret;
   1923   1.1  riastrad }
   1924  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_initial_config);
   1925   1.1  riastrad 
   1926  1.17  riastrad /**
   1927  1.17  riastrad  * drm_fb_helper_hotplug_event - respond to a hotplug notification by
   1928  1.17  riastrad  *                               probing all the outputs attached to the fb
   1929  1.17  riastrad  * @fb_helper: driver-allocated fbdev helper, can be NULL
   1930  1.17  riastrad  *
   1931  1.17  riastrad  * Scan the connectors attached to the fb_helper and try to put together a
   1932  1.17  riastrad  * setup after notification of a change in output configuration.
   1933  1.17  riastrad  *
   1934  1.17  riastrad  * Called at runtime, takes the mode config locks to be able to check/change the
   1935  1.17  riastrad  * modeset configuration. Must be run from process context (which usually means
   1936  1.17  riastrad  * either the output polling work or a work item launched from the driver's
   1937  1.17  riastrad  * hotplug interrupt).
   1938  1.17  riastrad  *
   1939  1.17  riastrad  * Note that drivers may call this even before calling
   1940  1.17  riastrad  * drm_fb_helper_initial_config but only after drm_fb_helper_init. This allows
   1941  1.17  riastrad  * for a race-free fbcon setup and will make sure that the fbdev emulation will
   1942  1.17  riastrad  * not miss any hotplug events.
   1943  1.17  riastrad  *
   1944  1.17  riastrad  * RETURNS:
   1945  1.17  riastrad  * 0 on success and a non-zero error code otherwise.
   1946  1.17  riastrad  */
   1947  1.17  riastrad int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
   1948   1.1  riastrad {
   1949  1.17  riastrad 	int err = 0;
   1950   1.1  riastrad 
   1951  1.17  riastrad 	if (!drm_fbdev_emulation || !fb_helper)
   1952  1.17  riastrad 		return 0;
   1953   1.1  riastrad 
   1954  1.17  riastrad 	mutex_lock(&fb_helper->lock);
   1955  1.17  riastrad 	if (fb_helper->deferred_setup) {
   1956  1.17  riastrad 		err = __drm_fb_helper_initial_config_and_unlock(fb_helper,
   1957  1.17  riastrad 				fb_helper->preferred_bpp);
   1958  1.17  riastrad 		return err;
   1959   1.1  riastrad 	}
   1960   1.1  riastrad 
   1961  1.17  riastrad 	if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
   1962  1.17  riastrad 		fb_helper->delayed_hotplug = true;
   1963  1.17  riastrad 		mutex_unlock(&fb_helper->lock);
   1964  1.17  riastrad 		return err;
   1965   1.1  riastrad 	}
   1966   1.1  riastrad 
   1967  1.17  riastrad 	drm_master_internal_release(fb_helper->dev);
   1968   1.1  riastrad 
   1969  1.17  riastrad 	drm_dbg_kms(fb_helper->dev, "\n");
   1970   1.1  riastrad 
   1971  1.17  riastrad 	drm_client_modeset_probe(&fb_helper->client, fb_helper->fb->width, fb_helper->fb->height);
   1972  1.17  riastrad 	drm_setup_crtcs_fb(fb_helper);
   1973  1.17  riastrad 	mutex_unlock(&fb_helper->lock);
   1974   1.1  riastrad 
   1975  1.17  riastrad #ifdef __NetBSD__
   1976  1.17  riastrad 	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
   1977  1.17  riastrad #else
   1978  1.17  riastrad 	drm_fb_helper_set_par(fb_helper->fbdev);
   1979  1.17  riastrad #endif
   1980   1.1  riastrad 
   1981  1.17  riastrad 	return 0;
   1982  1.17  riastrad }
   1983  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
   1984   1.1  riastrad 
   1985  1.17  riastrad /**
   1986  1.17  riastrad  * drm_fb_helper_lastclose - DRM driver lastclose helper for fbdev emulation
   1987  1.17  riastrad  * @dev: DRM device
   1988  1.17  riastrad  *
   1989  1.17  riastrad  * This function can be used as the &drm_driver->lastclose callback for drivers
   1990  1.17  riastrad  * that only need to call drm_fb_helper_restore_fbdev_mode_unlocked().
   1991  1.17  riastrad  */
   1992  1.17  riastrad void drm_fb_helper_lastclose(struct drm_device *dev)
   1993  1.17  riastrad {
   1994  1.17  riastrad 	drm_fb_helper_restore_fbdev_mode_unlocked(dev->fb_helper);
   1995   1.1  riastrad }
   1996  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_lastclose);
   1997   1.1  riastrad 
   1998  1.17  riastrad /**
   1999  1.17  riastrad  * drm_fb_helper_output_poll_changed - DRM mode config \.output_poll_changed
   2000  1.17  riastrad  *                                     helper for fbdev emulation
   2001  1.17  riastrad  * @dev: DRM device
   2002  1.17  riastrad  *
   2003  1.17  riastrad  * This function can be used as the
   2004  1.17  riastrad  * &drm_mode_config_funcs.output_poll_changed callback for drivers that only
   2005  1.17  riastrad  * need to call drm_fb_helper_hotplug_event().
   2006  1.17  riastrad  */
   2007  1.17  riastrad void drm_fb_helper_output_poll_changed(struct drm_device *dev)
   2008   1.9  riastrad {
   2009  1.17  riastrad 	drm_fb_helper_hotplug_event(dev->fb_helper);
   2010  1.17  riastrad }
   2011  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
   2012   1.9  riastrad 
   2013  1.20  riastrad #ifndef __NetBSD__		/* XXX fb info */
   2014  1.20  riastrad 
   2015  1.17  riastrad /* @user: 1=userspace, 0=fbcon */
   2016  1.17  riastrad static int drm_fbdev_fb_open(struct fb_info *info, int user)
   2017  1.17  riastrad {
   2018  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   2019   1.9  riastrad 
   2020  1.17  riastrad 	/* No need to take a ref for fbcon because it unbinds on unregister */
   2021  1.17  riastrad 	if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
   2022  1.17  riastrad 		return -ENODEV;
   2023   1.9  riastrad 
   2024   1.9  riastrad 	return 0;
   2025   1.9  riastrad }
   2026   1.9  riastrad 
   2027  1.17  riastrad static int drm_fbdev_fb_release(struct fb_info *info, int user)
   2028   1.1  riastrad {
   2029  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   2030   1.1  riastrad 
   2031  1.17  riastrad 	if (user)
   2032  1.17  riastrad 		module_put(fb_helper->dev->driver->fops->owner);
   2033   1.9  riastrad 
   2034  1.17  riastrad 	return 0;
   2035  1.17  riastrad }
   2036   1.9  riastrad 
   2037  1.22  riastrad #endif	/* __NetBSD__ */
   2038  1.22  riastrad 
   2039  1.17  riastrad static void drm_fbdev_cleanup(struct drm_fb_helper *fb_helper)
   2040  1.17  riastrad {
   2041  1.22  riastrad #ifndef __NetBSD__		/* XXX fb info */
   2042  1.17  riastrad 	struct fb_info *fbi = fb_helper->fbdev;
   2043  1.22  riastrad #endif
   2044  1.17  riastrad 	void *shadow = NULL;
   2045   1.1  riastrad 
   2046  1.17  riastrad 	if (!fb_helper->dev)
   2047  1.17  riastrad 		return;
   2048   1.9  riastrad 
   2049  1.22  riastrad #ifndef __NetBSD__		/* XXX fb info */
   2050  1.17  riastrad 	if (fbi && fbi->fbdefio) {
   2051  1.17  riastrad 		fb_deferred_io_cleanup(fbi);
   2052  1.17  riastrad 		shadow = fbi->screen_buffer;
   2053  1.17  riastrad 	}
   2054  1.22  riastrad #endif
   2055   1.9  riastrad 
   2056  1.17  riastrad 	drm_fb_helper_fini(fb_helper);
   2057   1.1  riastrad 
   2058  1.17  riastrad 	vfree(shadow);
   2059   1.9  riastrad 
   2060  1.17  riastrad 	drm_client_framebuffer_delete(fb_helper->buffer);
   2061   1.1  riastrad }
   2062   1.1  riastrad 
   2063  1.17  riastrad static void drm_fbdev_release(struct drm_fb_helper *fb_helper)
   2064   1.1  riastrad {
   2065  1.17  riastrad 	drm_fbdev_cleanup(fb_helper);
   2066  1.17  riastrad 	drm_client_release(&fb_helper->client);
   2067  1.17  riastrad 	kfree(fb_helper);
   2068  1.17  riastrad }
   2069   1.1  riastrad 
   2070  1.22  riastrad 
   2071  1.22  riastrad #ifndef __NetBSD__		/* XXX fb info */
   2072  1.17  riastrad /*
   2073  1.17  riastrad  * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
   2074  1.17  riastrad  * unregister_framebuffer() or fb_release().
   2075  1.17  riastrad  */
   2076  1.17  riastrad static void drm_fbdev_fb_destroy(struct fb_info *info)
   2077  1.17  riastrad {
   2078  1.17  riastrad 	drm_fbdev_release(info->par);
   2079  1.17  riastrad }
   2080   1.1  riastrad 
   2081  1.17  riastrad static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
   2082  1.17  riastrad {
   2083  1.17  riastrad 	struct drm_fb_helper *fb_helper = info->par;
   2084   1.1  riastrad 
   2085  1.17  riastrad 	if (fb_helper->dev->driver->gem_prime_mmap)
   2086  1.17  riastrad 		return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
   2087  1.17  riastrad 	else
   2088  1.17  riastrad 		return -ENODEV;
   2089  1.17  riastrad }
   2090   1.1  riastrad 
   2091  1.17  riastrad static const struct fb_ops drm_fbdev_fb_ops = {
   2092  1.17  riastrad 	.owner		= THIS_MODULE,
   2093  1.17  riastrad 	DRM_FB_HELPER_DEFAULT_OPS,
   2094  1.17  riastrad 	.fb_open	= drm_fbdev_fb_open,
   2095  1.17  riastrad 	.fb_release	= drm_fbdev_fb_release,
   2096  1.17  riastrad 	.fb_destroy	= drm_fbdev_fb_destroy,
   2097  1.17  riastrad 	.fb_mmap	= drm_fbdev_fb_mmap,
   2098  1.17  riastrad 	.fb_read	= drm_fb_helper_sys_read,
   2099  1.17  riastrad 	.fb_write	= drm_fb_helper_sys_write,
   2100  1.17  riastrad 	.fb_fillrect	= drm_fb_helper_sys_fillrect,
   2101  1.17  riastrad 	.fb_copyarea	= drm_fb_helper_sys_copyarea,
   2102  1.17  riastrad 	.fb_imageblit	= drm_fb_helper_sys_imageblit,
   2103  1.17  riastrad };
   2104   1.1  riastrad 
   2105  1.17  riastrad static struct fb_deferred_io drm_fbdev_defio = {
   2106  1.17  riastrad 	.delay		= HZ / 20,
   2107  1.17  riastrad 	.deferred_io	= drm_fb_helper_deferred_io,
   2108  1.17  riastrad };
   2109   1.1  riastrad 
   2110  1.20  riastrad #endif	/* __NetBSD__ */
   2111  1.17  riastrad /*
   2112  1.17  riastrad  * This function uses the client API to create a framebuffer backed by a dumb buffer.
   2113  1.17  riastrad  *
   2114  1.17  riastrad  * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect,
   2115  1.17  riastrad  * fb_copyarea, fb_imageblit.
   2116  1.17  riastrad  */
   2117  1.17  riastrad static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
   2118  1.17  riastrad 				       struct drm_fb_helper_surface_size *sizes)
   2119  1.17  riastrad {
   2120  1.17  riastrad 	struct drm_client_dev *client = &fb_helper->client;
   2121  1.17  riastrad 	struct drm_device *dev = fb_helper->dev;
   2122  1.17  riastrad 	struct drm_client_buffer *buffer;
   2123  1.17  riastrad 	struct drm_framebuffer *fb;
   2124  1.20  riastrad #ifndef __NetBSD__		/* XXX fb info */
   2125  1.17  riastrad 	struct fb_info *fbi;
   2126  1.20  riastrad #endif
   2127  1.17  riastrad 	u32 format;
   2128  1.17  riastrad 	void *vaddr;
   2129  1.17  riastrad 
   2130  1.17  riastrad 	drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
   2131  1.17  riastrad 		    sizes->surface_width, sizes->surface_height,
   2132  1.17  riastrad 		    sizes->surface_bpp);
   2133  1.17  riastrad 
   2134  1.17  riastrad 	format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
   2135  1.17  riastrad 	buffer = drm_client_framebuffer_create(client, sizes->surface_width,
   2136  1.17  riastrad 					       sizes->surface_height, format);
   2137  1.17  riastrad 	if (IS_ERR(buffer))
   2138  1.17  riastrad 		return PTR_ERR(buffer);
   2139  1.17  riastrad 
   2140  1.17  riastrad 	fb_helper->buffer = buffer;
   2141  1.17  riastrad 	fb_helper->fb = buffer->fb;
   2142  1.17  riastrad 	fb = buffer->fb;
   2143  1.17  riastrad 
   2144  1.20  riastrad #ifdef __NetBSD__		/* XXX fb info */
   2145  1.20  riastrad 	__USE(fb);
   2146  1.22  riastrad 	__USE(vaddr);
   2147  1.20  riastrad #else
   2148  1.17  riastrad 	fbi = drm_fb_helper_alloc_fbi(fb_helper);
   2149  1.17  riastrad 	if (IS_ERR(fbi))
   2150  1.17  riastrad 		return PTR_ERR(fbi);
   2151  1.17  riastrad 
   2152  1.17  riastrad 	fbi->fbops = &drm_fbdev_fb_ops;
   2153  1.17  riastrad 	fbi->screen_size = fb->height * fb->pitches[0];
   2154  1.17  riastrad 	fbi->fix.smem_len = fbi->screen_size;
   2155  1.17  riastrad 
   2156  1.17  riastrad 	drm_fb_helper_fill_info(fbi, fb_helper, sizes);
   2157  1.17  riastrad 
   2158  1.17  riastrad 	if (drm_fbdev_use_shadow_fb(fb_helper)) {
   2159  1.17  riastrad 		fbi->screen_buffer = vzalloc(fbi->screen_size);
   2160  1.17  riastrad 		if (!fbi->screen_buffer)
   2161  1.17  riastrad 			return -ENOMEM;
   2162   1.1  riastrad 
   2163  1.17  riastrad 		fbi->fbdefio = &drm_fbdev_defio;
   2164   1.1  riastrad 
   2165  1.17  riastrad 		fb_deferred_io_init(fbi);
   2166  1.17  riastrad 	} else {
   2167  1.17  riastrad 		/* buffer is mapped for HW framebuffer */
   2168  1.17  riastrad 		vaddr = drm_client_buffer_vmap(fb_helper->buffer);
   2169  1.17  riastrad 		if (IS_ERR(vaddr))
   2170  1.17  riastrad 			return PTR_ERR(vaddr);
   2171  1.17  riastrad 
   2172  1.17  riastrad 		fbi->screen_buffer = vaddr;
   2173  1.17  riastrad 		/* Shamelessly leak the physical address to user-space */
   2174  1.17  riastrad #if IS_ENABLED(CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM)
   2175  1.17  riastrad 		if (drm_leak_fbdev_smem && fbi->fix.smem_start == 0)
   2176  1.17  riastrad 			fbi->fix.smem_start =
   2177  1.17  riastrad 				page_to_phys(virt_to_page(fbi->screen_buffer));
   2178  1.17  riastrad #endif
   2179   1.1  riastrad 	}
   2180  1.20  riastrad #endif	/* __NetBSD__ */
   2181  1.17  riastrad 
   2182  1.17  riastrad 	return 0;
   2183   1.1  riastrad }
   2184   1.1  riastrad 
   2185  1.17  riastrad static const struct drm_fb_helper_funcs drm_fb_helper_generic_funcs = {
   2186  1.17  riastrad 	.fb_probe = drm_fb_helper_generic_probe,
   2187  1.17  riastrad };
   2188  1.17  riastrad 
   2189  1.17  riastrad static void drm_fbdev_client_unregister(struct drm_client_dev *client)
   2190   1.1  riastrad {
   2191  1.17  riastrad 	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
   2192   1.1  riastrad 
   2193  1.22  riastrad #ifndef __NetBSD__		/* XXX fb info */
   2194  1.17  riastrad 	if (fb_helper->fbdev)
   2195  1.17  riastrad 		/* drm_fbdev_fb_destroy() takes care of cleanup */
   2196  1.17  riastrad 		drm_fb_helper_unregister_fbi(fb_helper);
   2197  1.22  riastrad 	else
   2198  1.20  riastrad #endif
   2199  1.17  riastrad 		drm_fbdev_release(fb_helper);
   2200  1.17  riastrad }
   2201   1.1  riastrad 
   2202  1.17  riastrad static int drm_fbdev_client_restore(struct drm_client_dev *client)
   2203  1.17  riastrad {
   2204  1.17  riastrad 	drm_fb_helper_lastclose(client->dev);
   2205   1.1  riastrad 
   2206  1.17  riastrad 	return 0;
   2207   1.1  riastrad }
   2208   1.1  riastrad 
   2209  1.17  riastrad static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
   2210   1.1  riastrad {
   2211  1.17  riastrad 	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
   2212  1.17  riastrad 	struct drm_device *dev = client->dev;
   2213  1.17  riastrad 	int ret;
   2214  1.17  riastrad 
   2215  1.17  riastrad 	/* Setup is not retried if it has failed */
   2216  1.17  riastrad 	if (!fb_helper->dev && fb_helper->funcs)
   2217  1.17  riastrad 		return 0;
   2218  1.17  riastrad 
   2219  1.17  riastrad 	if (dev->fb_helper)
   2220  1.17  riastrad 		return drm_fb_helper_hotplug_event(dev->fb_helper);
   2221   1.1  riastrad 
   2222  1.17  riastrad 	if (!dev->mode_config.num_connector) {
   2223  1.17  riastrad 		drm_dbg_kms(dev, "No connectors found, will not create framebuffer!\n");
   2224   1.9  riastrad 		return 0;
   2225  1.17  riastrad 	}
   2226  1.17  riastrad 
   2227  1.17  riastrad 	drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs);
   2228  1.17  riastrad 
   2229  1.17  riastrad 	ret = drm_fb_helper_init(dev, fb_helper, 0);
   2230  1.17  riastrad 	if (ret)
   2231  1.17  riastrad 		goto err;
   2232  1.17  riastrad 
   2233  1.17  riastrad 	if (!drm_drv_uses_atomic_modeset(dev))
   2234  1.17  riastrad 		drm_helper_disable_unused_functions(dev);
   2235  1.17  riastrad 
   2236  1.17  riastrad 	ret = drm_fb_helper_initial_config(fb_helper, fb_helper->preferred_bpp);
   2237  1.17  riastrad 	if (ret)
   2238  1.17  riastrad 		goto err_cleanup;
   2239  1.17  riastrad 
   2240  1.17  riastrad 	return 0;
   2241   1.1  riastrad 
   2242  1.17  riastrad err_cleanup:
   2243  1.17  riastrad 	drm_fbdev_cleanup(fb_helper);
   2244  1.17  riastrad err:
   2245  1.17  riastrad 	fb_helper->dev = NULL;
   2246  1.17  riastrad 	fb_helper->fbdev = NULL;
   2247   1.1  riastrad 
   2248  1.17  riastrad 	drm_err(dev, "fbdev: Failed to setup generic emulation (ret=%d)\n", ret);
   2249   1.1  riastrad 
   2250  1.17  riastrad 	return ret;
   2251   1.1  riastrad }
   2252  1.17  riastrad 
   2253  1.17  riastrad static const struct drm_client_funcs drm_fbdev_client_funcs = {
   2254  1.17  riastrad 	.owner		= THIS_MODULE,
   2255  1.17  riastrad 	.unregister	= drm_fbdev_client_unregister,
   2256  1.17  riastrad 	.restore	= drm_fbdev_client_restore,
   2257  1.17  riastrad 	.hotplug	= drm_fbdev_client_hotplug,
   2258  1.17  riastrad };
   2259   1.1  riastrad 
   2260   1.1  riastrad /**
   2261  1.17  riastrad  * drm_fbdev_generic_setup() - Setup generic fbdev emulation
   2262  1.17  riastrad  * @dev: DRM device
   2263  1.17  riastrad  * @preferred_bpp: Preferred bits per pixel for the device.
   2264  1.17  riastrad  *                 @dev->mode_config.preferred_depth is used if this is zero.
   2265  1.17  riastrad  *
   2266  1.17  riastrad  * This function sets up generic fbdev emulation for drivers that supports
   2267  1.17  riastrad  * dumb buffers with a virtual address and that can be mmap'ed.
   2268  1.17  riastrad  *
   2269  1.17  riastrad  * Restore, hotplug events and teardown are all taken care of. Drivers that do
   2270  1.17  riastrad  * suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
   2271  1.17  riastrad  * Simple drivers might use drm_mode_config_helper_suspend().
   2272   1.1  riastrad  *
   2273  1.17  riastrad  * Drivers that set the dirty callback on their framebuffer will get a shadow
   2274  1.17  riastrad  * fbdev buffer that is blitted onto the real buffer. This is done in order to
   2275  1.17  riastrad  * make deferred I/O work with all kinds of buffers. A shadow buffer can be
   2276  1.17  riastrad  * requested explicitly by setting struct drm_mode_config.prefer_shadow or
   2277  1.17  riastrad  * struct drm_mode_config.prefer_shadow_fbdev to true beforehand. This is
   2278  1.17  riastrad  * required to use generic fbdev emulation with SHMEM helpers.
   2279   1.1  riastrad  *
   2280  1.17  riastrad  * This function is safe to call even when there are no connectors present.
   2281  1.17  riastrad  * Setup will be retried on the next hotplug event.
   2282   1.5  riastrad  *
   2283  1.17  riastrad  * The fbdev is destroyed by drm_dev_unregister().
   2284   1.5  riastrad  *
   2285  1.17  riastrad  * Returns:
   2286  1.17  riastrad  * Zero on success or negative error code on failure.
   2287   1.1  riastrad  */
   2288  1.17  riastrad int drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
   2289   1.1  riastrad {
   2290  1.17  riastrad 	struct drm_fb_helper *fb_helper;
   2291  1.17  riastrad 	int ret;
   2292  1.17  riastrad 
   2293  1.17  riastrad 	WARN(dev->fb_helper, "fb_helper is already set!\n");
   2294   1.1  riastrad 
   2295   1.9  riastrad 	if (!drm_fbdev_emulation)
   2296   1.1  riastrad 		return 0;
   2297   1.1  riastrad 
   2298  1.17  riastrad 	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
   2299  1.17  riastrad 	if (!fb_helper)
   2300  1.17  riastrad 		return -ENOMEM;
   2301  1.17  riastrad 
   2302  1.17  riastrad 	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
   2303  1.17  riastrad 	if (ret) {
   2304  1.17  riastrad 		kfree(fb_helper);
   2305  1.17  riastrad 		drm_err(dev, "Failed to register client: %d\n", ret);
   2306  1.17  riastrad 		return ret;
   2307   1.1  riastrad 	}
   2308   1.1  riastrad 
   2309  1.17  riastrad 	if (!preferred_bpp)
   2310  1.17  riastrad 		preferred_bpp = dev->mode_config.preferred_depth;
   2311  1.17  riastrad 	if (!preferred_bpp)
   2312  1.17  riastrad 		preferred_bpp = 32;
   2313  1.17  riastrad 	fb_helper->preferred_bpp = preferred_bpp;
   2314   1.1  riastrad 
   2315  1.17  riastrad 	ret = drm_fbdev_client_hotplug(&fb_helper->client);
   2316  1.17  riastrad 	if (ret)
   2317  1.17  riastrad 		drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
   2318   1.5  riastrad 
   2319  1.17  riastrad 	drm_client_register(&fb_helper->client);
   2320   1.1  riastrad 
   2321   1.5  riastrad 	return 0;
   2322   1.1  riastrad }
   2323  1.17  riastrad EXPORT_SYMBOL(drm_fbdev_generic_setup);
   2324   1.1  riastrad 
   2325   1.1  riastrad /* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
   2326   1.1  riastrad  * but the module doesn't depend on any fb console symbols.  At least
   2327   1.1  riastrad  * attempt to load fbcon to avoid leaving the system without a usable console.
   2328   1.1  riastrad  */
   2329  1.17  riastrad int __init drm_fb_helper_modinit(void)
   2330  1.17  riastrad {
   2331   1.1  riastrad #if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
   2332  1.17  riastrad 	const char name[] = "fbcon";
   2333   1.1  riastrad 	struct module *fbcon;
   2334   1.1  riastrad 
   2335   1.1  riastrad 	mutex_lock(&module_mutex);
   2336   1.1  riastrad 	fbcon = find_module(name);
   2337   1.1  riastrad 	mutex_unlock(&module_mutex);
   2338   1.1  riastrad 
   2339   1.1  riastrad 	if (!fbcon)
   2340   1.1  riastrad 		request_module_nowait(name);
   2341  1.17  riastrad #endif
   2342   1.1  riastrad 	return 0;
   2343   1.1  riastrad }
   2344  1.17  riastrad EXPORT_SYMBOL(drm_fb_helper_modinit);
   2345