Home | History | Annotate | Line # | Download | only in display
      1  1.10       chs /*	$NetBSD: intel_fbdev.c,v 1.10 2021/12/20 20:34:58 chs Exp $	*/
      2   1.1  riastrad 
      3   1.1  riastrad /*
      4   1.1  riastrad  * Copyright  2007 David Airlie
      5   1.1  riastrad  *
      6   1.1  riastrad  * Permission is hereby granted, free of charge, to any person obtaining a
      7   1.1  riastrad  * copy of this software and associated documentation files (the "Software"),
      8   1.1  riastrad  * to deal in the Software without restriction, including without limitation
      9   1.1  riastrad  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10   1.1  riastrad  * and/or sell copies of the Software, and to permit persons to whom the
     11   1.1  riastrad  * Software is furnished to do so, subject to the following conditions:
     12   1.1  riastrad  *
     13   1.1  riastrad  * The above copyright notice and this permission notice (including the next
     14   1.1  riastrad  * paragraph) shall be included in all copies or substantial portions of the
     15   1.1  riastrad  * Software.
     16   1.1  riastrad  *
     17   1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18   1.1  riastrad  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19   1.1  riastrad  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20   1.1  riastrad  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21   1.1  riastrad  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     22   1.1  riastrad  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     23   1.1  riastrad  * DEALINGS IN THE SOFTWARE.
     24   1.1  riastrad  *
     25   1.1  riastrad  * Authors:
     26   1.1  riastrad  *     David Airlie
     27   1.1  riastrad  */
     28   1.1  riastrad 
     29   1.1  riastrad #include <sys/cdefs.h>
     30  1.10       chs __KERNEL_RCSID(0, "$NetBSD: intel_fbdev.c,v 1.10 2021/12/20 20:34:58 chs Exp $");
     31   1.1  riastrad 
     32   1.1  riastrad #include <linux/async.h>
     33   1.1  riastrad #include <linux/console.h>
     34   1.1  riastrad #include <linux/delay.h>
     35   1.1  riastrad #include <linux/errno.h>
     36   1.1  riastrad #include <linux/init.h>
     37   1.1  riastrad #include <linux/kernel.h>
     38   1.1  riastrad #include <linux/mm.h>
     39   1.1  riastrad #include <linux/module.h>
     40   1.1  riastrad #include <linux/string.h>
     41   1.1  riastrad #include <linux/sysrq.h>
     42   1.1  riastrad #include <linux/tty.h>
     43   1.1  riastrad #include <linux/vga_switcheroo.h>
     44   1.1  riastrad 
     45   1.1  riastrad #include <drm/drm_crtc.h>
     46   1.1  riastrad #include <drm/drm_fb_helper.h>
     47   1.1  riastrad #include <drm/drm_fourcc.h>
     48   1.1  riastrad #include <drm/i915_drm.h>
     49   1.1  riastrad 
     50   1.1  riastrad #include "i915_drv.h"
     51   1.1  riastrad #include "intel_display_types.h"
     52   1.1  riastrad #include "intel_fbdev.h"
     53   1.1  riastrad #include "intel_frontbuffer.h"
     54   1.1  riastrad 
     55   1.1  riastrad static struct intel_frontbuffer *to_frontbuffer(struct intel_fbdev *ifbdev)
     56   1.1  riastrad {
     57   1.1  riastrad 	return ifbdev->fb->frontbuffer;
     58   1.1  riastrad }
     59   1.1  riastrad 
     60   1.1  riastrad static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev)
     61   1.1  riastrad {
     62   1.1  riastrad 	intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU);
     63   1.1  riastrad }
     64   1.1  riastrad 
     65   1.2  riastrad #ifdef __NetBSD__
     66   1.2  riastrad #include "intelfb.h"
     67   1.2  riastrad #include <linux/nbsd-namespace.h>
     68   1.2  riastrad #endif
     69   1.2  riastrad 
     70   1.2  riastrad #ifndef __NetBSD__
     71   1.1  riastrad static int intel_fbdev_set_par(struct fb_info *info)
     72   1.1  riastrad {
     73   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
     74   1.1  riastrad 	struct intel_fbdev *ifbdev =
     75   1.1  riastrad 		container_of(fb_helper, struct intel_fbdev, helper);
     76   1.1  riastrad 	int ret;
     77   1.1  riastrad 
     78   1.1  riastrad 	ret = drm_fb_helper_set_par(info);
     79   1.1  riastrad 	if (ret == 0)
     80   1.1  riastrad 		intel_fbdev_invalidate(ifbdev);
     81   1.1  riastrad 
     82   1.1  riastrad 	return ret;
     83   1.1  riastrad }
     84   1.1  riastrad 
     85   1.1  riastrad static int intel_fbdev_blank(int blank, struct fb_info *info)
     86   1.1  riastrad {
     87   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
     88   1.1  riastrad 	struct intel_fbdev *ifbdev =
     89   1.1  riastrad 		container_of(fb_helper, struct intel_fbdev, helper);
     90   1.1  riastrad 	int ret;
     91   1.1  riastrad 
     92   1.1  riastrad 	ret = drm_fb_helper_blank(blank, info);
     93   1.1  riastrad 	if (ret == 0)
     94   1.1  riastrad 		intel_fbdev_invalidate(ifbdev);
     95   1.1  riastrad 
     96   1.1  riastrad 	return ret;
     97   1.1  riastrad }
     98   1.1  riastrad 
     99   1.1  riastrad static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
    100   1.1  riastrad 				   struct fb_info *info)
    101   1.1  riastrad {
    102   1.1  riastrad 	struct drm_fb_helper *fb_helper = info->par;
    103   1.1  riastrad 	struct intel_fbdev *ifbdev =
    104   1.1  riastrad 		container_of(fb_helper, struct intel_fbdev, helper);
    105   1.1  riastrad 	int ret;
    106   1.1  riastrad 
    107   1.1  riastrad 	ret = drm_fb_helper_pan_display(var, info);
    108   1.1  riastrad 	if (ret == 0)
    109   1.1  riastrad 		intel_fbdev_invalidate(ifbdev);
    110   1.1  riastrad 
    111   1.1  riastrad 	return ret;
    112   1.1  riastrad }
    113   1.1  riastrad 
    114   1.1  riastrad static const struct fb_ops intelfb_ops = {
    115   1.1  riastrad 	.owner = THIS_MODULE,
    116   1.1  riastrad 	DRM_FB_HELPER_DEFAULT_OPS,
    117   1.1  riastrad 	.fb_set_par = intel_fbdev_set_par,
    118   1.1  riastrad 	.fb_fillrect = drm_fb_helper_cfb_fillrect,
    119   1.1  riastrad 	.fb_copyarea = drm_fb_helper_cfb_copyarea,
    120   1.1  riastrad 	.fb_imageblit = drm_fb_helper_cfb_imageblit,
    121   1.1  riastrad 	.fb_pan_display = intel_fbdev_pan_display,
    122   1.1  riastrad 	.fb_blank = intel_fbdev_blank,
    123   1.1  riastrad };
    124   1.2  riastrad #endif
    125   1.1  riastrad 
    126   1.1  riastrad static int intelfb_alloc(struct drm_fb_helper *helper,
    127   1.1  riastrad 			 struct drm_fb_helper_surface_size *sizes)
    128   1.1  riastrad {
    129   1.1  riastrad 	struct intel_fbdev *ifbdev =
    130   1.1  riastrad 		container_of(helper, struct intel_fbdev, helper);
    131   1.1  riastrad 	struct drm_framebuffer *fb;
    132   1.1  riastrad 	struct drm_device *dev = helper->dev;
    133   1.1  riastrad 	struct drm_i915_private *dev_priv = to_i915(dev);
    134   1.1  riastrad 	struct drm_mode_fb_cmd2 mode_cmd = {};
    135   1.1  riastrad 	struct drm_i915_gem_object *obj;
    136   1.1  riastrad 	int size;
    137   1.1  riastrad 
    138   1.1  riastrad 	/* we don't do packed 24bpp */
    139   1.1  riastrad 	if (sizes->surface_bpp == 24)
    140   1.1  riastrad 		sizes->surface_bpp = 32;
    141   1.1  riastrad 
    142   1.1  riastrad 	mode_cmd.width = sizes->surface_width;
    143   1.1  riastrad 	mode_cmd.height = sizes->surface_height;
    144   1.1  riastrad 
    145   1.1  riastrad 	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
    146   1.1  riastrad 				    DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
    147   1.1  riastrad 	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
    148   1.1  riastrad 							  sizes->surface_depth);
    149   1.1  riastrad 
    150   1.1  riastrad 	size = mode_cmd.pitches[0] * mode_cmd.height;
    151   1.1  riastrad 	size = PAGE_ALIGN(size);
    152   1.1  riastrad 
    153   1.1  riastrad 	/* If the FB is too big, just don't use it since fbdev is not very
    154   1.1  riastrad 	 * important and we should probably use that space with FBC or other
    155   1.1  riastrad 	 * features. */
    156   1.1  riastrad 	obj = ERR_PTR(-ENODEV);
    157   1.1  riastrad 	if (size * 2 < dev_priv->stolen_usable_size)
    158   1.1  riastrad 		obj = i915_gem_object_create_stolen(dev_priv, size);
    159   1.1  riastrad 	if (IS_ERR(obj))
    160   1.1  riastrad 		obj = i915_gem_object_create_shmem(dev_priv, size);
    161   1.1  riastrad 	if (IS_ERR(obj)) {
    162   1.1  riastrad 		DRM_ERROR("failed to allocate framebuffer\n");
    163   1.1  riastrad 		return PTR_ERR(obj);
    164   1.1  riastrad 	}
    165   1.1  riastrad 
    166   1.1  riastrad 	fb = intel_framebuffer_create(obj, &mode_cmd);
    167   1.1  riastrad 	i915_gem_object_put(obj);
    168   1.1  riastrad 	if (IS_ERR(fb))
    169   1.1  riastrad 		return PTR_ERR(fb);
    170   1.1  riastrad 
    171   1.1  riastrad 	ifbdev->fb = to_intel_framebuffer(fb);
    172   1.1  riastrad 	return 0;
    173   1.1  riastrad }
    174   1.1  riastrad 
    175   1.4  riastrad #ifdef __NetBSD__
    176   1.4  riastrad #  define	__iomem		__i915_vma_iomem
    177   1.4  riastrad #endif
    178   1.4  riastrad 
    179   1.1  riastrad static int intelfb_create(struct drm_fb_helper *helper,
    180   1.1  riastrad 			  struct drm_fb_helper_surface_size *sizes)
    181   1.1  riastrad {
    182   1.1  riastrad 	struct intel_fbdev *ifbdev =
    183   1.1  riastrad 		container_of(helper, struct intel_fbdev, helper);
    184   1.1  riastrad 	struct intel_framebuffer *intel_fb = ifbdev->fb;
    185   1.1  riastrad 	struct drm_device *dev = helper->dev;
    186   1.1  riastrad 	struct drm_i915_private *dev_priv = to_i915(dev);
    187   1.1  riastrad 	struct pci_dev *pdev = dev_priv->drm.pdev;
    188   1.1  riastrad 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
    189   1.1  riastrad 	const struct i915_ggtt_view view = {
    190   1.1  riastrad 		.type = I915_GGTT_VIEW_NORMAL,
    191   1.1  riastrad 	};
    192   1.1  riastrad 	intel_wakeref_t wakeref;
    193   1.2  riastrad #ifndef __NetBSD__
    194   1.1  riastrad 	struct fb_info *info;
    195   1.2  riastrad #endif
    196   1.1  riastrad 	struct i915_vma *vma;
    197   1.1  riastrad 	unsigned long flags = 0;
    198   1.1  riastrad 	bool prealloc = false;
    199   1.1  riastrad 	void __iomem *vaddr;
    200   1.1  riastrad 	int ret;
    201   1.1  riastrad 
    202   1.1  riastrad 	if (intel_fb &&
    203   1.1  riastrad 	    (sizes->fb_width > intel_fb->base.width ||
    204   1.1  riastrad 	     sizes->fb_height > intel_fb->base.height)) {
    205   1.1  riastrad 		DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d),"
    206   1.1  riastrad 			      " releasing it\n",
    207   1.1  riastrad 			      intel_fb->base.width, intel_fb->base.height,
    208   1.1  riastrad 			      sizes->fb_width, sizes->fb_height);
    209   1.1  riastrad 		drm_framebuffer_put(&intel_fb->base);
    210   1.1  riastrad 		intel_fb = ifbdev->fb = NULL;
    211   1.1  riastrad 	}
    212   1.1  riastrad 	if (!intel_fb || WARN_ON(!intel_fb_obj(&intel_fb->base))) {
    213   1.1  riastrad 		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
    214   1.1  riastrad 		ret = intelfb_alloc(helper, sizes);
    215   1.1  riastrad 		if (ret)
    216   1.1  riastrad 			return ret;
    217   1.1  riastrad 		intel_fb = ifbdev->fb;
    218   1.1  riastrad 	} else {
    219   1.1  riastrad 		DRM_DEBUG_KMS("re-using BIOS fb\n");
    220   1.1  riastrad 		prealloc = true;
    221   1.1  riastrad 		sizes->fb_width = intel_fb->base.width;
    222   1.1  riastrad 		sizes->fb_height = intel_fb->base.height;
    223   1.1  riastrad 	}
    224   1.1  riastrad 
    225   1.1  riastrad 	wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
    226   1.1  riastrad 
    227   1.1  riastrad 	/* Pin the GGTT vma for our access via info->screen_base.
    228   1.1  riastrad 	 * This also validates that any existing fb inherited from the
    229   1.1  riastrad 	 * BIOS is suitable for own access.
    230   1.1  riastrad 	 */
    231   1.1  riastrad 	vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base,
    232   1.1  riastrad 					 &view, false, &flags);
    233   1.1  riastrad 	if (IS_ERR(vma)) {
    234   1.1  riastrad 		ret = PTR_ERR(vma);
    235   1.1  riastrad 		goto out_unlock;
    236   1.1  riastrad 	}
    237   1.1  riastrad 
    238   1.1  riastrad 	intel_frontbuffer_flush(to_frontbuffer(ifbdev), ORIGIN_DIRTYFB);
    239   1.1  riastrad 
    240   1.2  riastrad #ifdef __NetBSD__
    241   1.2  riastrad     {
    242   1.2  riastrad 	static const struct intelfb_attach_args zero_ifa;
    243   1.2  riastrad 	struct intelfb_attach_args ifa = zero_ifa;
    244   1.2  riastrad 
    245   1.4  riastrad 	__USE(ggtt);
    246   1.4  riastrad 	__USE(pdev);
    247   1.4  riastrad 
    248   1.4  riastrad 	vaddr = i915_vma_pin_iomap(vma);
    249   1.4  riastrad 	if (IS_ERR(vaddr)) {
    250   1.4  riastrad 		DRM_ERROR("Failed to remap framebuffer into virtual memory\n");
    251   1.4  riastrad 		ret = PTR_ERR(vaddr);
    252   1.4  riastrad 		goto out_unpin;
    253   1.4  riastrad 	}
    254   1.4  riastrad 
    255   1.4  riastrad         if (vma->obj->stolen && !prealloc)
    256   1.4  riastrad 		memset_io(vaddr, 0, vma->node.size);
    257   1.4  riastrad 
    258   1.2  riastrad 	ifa.ifa_drm_dev = dev;
    259   1.2  riastrad 	ifa.ifa_fb_helper = helper;
    260   1.2  riastrad 	ifa.ifa_fb_sizes = *sizes;
    261   1.4  riastrad 	ifa.ifa_fb_vaddr = vaddr;
    262   1.2  riastrad 
    263   1.2  riastrad 	/*
    264   1.2  riastrad 	 * XXX Should do this asynchronously, since we hold
    265   1.2  riastrad 	 * dev->struct_mutex.
    266   1.2  riastrad 	 */
    267  1.10       chs 	KERNEL_LOCK(1, NULL);
    268   1.2  riastrad 	helper->fbdev = config_found(dev->dev, &ifa, NULL,
    269   1.2  riastrad 	    CFARGS(.iattr = "intelfbbus"));
    270  1.10       chs 	KERNEL_UNLOCK_ONE(NULL);
    271   1.2  riastrad 	if (helper->fbdev == NULL) {
    272   1.2  riastrad 		DRM_ERROR("unable to attach intelfb\n");
    273   1.2  riastrad 		ret = -ENXIO;
    274   1.2  riastrad 		goto out_unpin;
    275   1.2  riastrad 	}
    276   1.4  riastrad 	ifbdev->helper.fb = &ifbdev->fb->base;
    277   1.2  riastrad     }
    278   1.2  riastrad #else
    279   1.1  riastrad 	info = drm_fb_helper_alloc_fbi(helper);
    280   1.1  riastrad 	if (IS_ERR(info)) {
    281   1.1  riastrad 		DRM_ERROR("Failed to allocate fb_info\n");
    282   1.1  riastrad 		ret = PTR_ERR(info);
    283   1.1  riastrad 		goto out_unpin;
    284   1.1  riastrad 	}
    285   1.1  riastrad 
    286   1.1  riastrad 	ifbdev->helper.fb = &ifbdev->fb->base;
    287   1.1  riastrad 
    288   1.1  riastrad 	info->fbops = &intelfb_ops;
    289   1.1  riastrad 
    290   1.1  riastrad 	/* setup aperture base/size for vesafb takeover */
    291   1.1  riastrad 	info->apertures->ranges[0].base = ggtt->gmadr.start;
    292   1.1  riastrad 	info->apertures->ranges[0].size = ggtt->mappable_end;
    293   1.1  riastrad 
    294   1.1  riastrad 	/* Our framebuffer is the entirety of fbdev's system memory */
    295   1.1  riastrad 	info->fix.smem_start =
    296   1.1  riastrad 		(unsigned long)(ggtt->gmadr.start + vma->node.start);
    297   1.1  riastrad 	info->fix.smem_len = vma->node.size;
    298   1.1  riastrad 
    299   1.1  riastrad 	vaddr = i915_vma_pin_iomap(vma);
    300   1.1  riastrad 	if (IS_ERR(vaddr)) {
    301   1.1  riastrad 		DRM_ERROR("Failed to remap framebuffer into virtual memory\n");
    302   1.1  riastrad 		ret = PTR_ERR(vaddr);
    303   1.1  riastrad 		goto out_unpin;
    304   1.1  riastrad 	}
    305   1.1  riastrad 	info->screen_base = vaddr;
    306   1.1  riastrad 	info->screen_size = vma->node.size;
    307   1.1  riastrad 
    308   1.1  riastrad 	drm_fb_helper_fill_info(info, &ifbdev->helper, sizes);
    309   1.1  riastrad 
    310   1.1  riastrad 	/* If the object is shmemfs backed, it will have given us zeroed pages.
    311   1.1  riastrad 	 * If the object is stolen however, it will be full of whatever
    312   1.1  riastrad 	 * garbage was left in there.
    313   1.1  riastrad 	 */
    314   1.1  riastrad 	if (vma->obj->stolen && !prealloc)
    315   1.1  riastrad 		memset_io(info->screen_base, 0, info->screen_size);
    316   1.2  riastrad #endif
    317   1.1  riastrad 
    318   1.1  riastrad 	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
    319   1.1  riastrad 
    320   1.5  riastrad 	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08"PRIx32"\n",
    321   1.1  riastrad 		      ifbdev->fb->base.width, ifbdev->fb->base.height,
    322   1.1  riastrad 		      i915_ggtt_offset(vma));
    323   1.1  riastrad 	ifbdev->vma = vma;
    324   1.1  riastrad 	ifbdev->vma_flags = flags;
    325   1.1  riastrad 
    326   1.1  riastrad 	intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
    327   1.2  riastrad #ifndef __NetBSD__
    328   1.1  riastrad 	vga_switcheroo_client_fb_set(pdev, info);
    329   1.2  riastrad #endif
    330   1.1  riastrad 	return 0;
    331   1.1  riastrad 
    332   1.1  riastrad out_unpin:
    333   1.1  riastrad 	intel_unpin_fb_vma(vma, flags);
    334   1.1  riastrad out_unlock:
    335   1.1  riastrad 	intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref);
    336   1.1  riastrad 	return ret;
    337   1.1  riastrad }
    338   1.6  riastrad 
    339   1.4  riastrad #ifdef __NetBSD__
    340   1.4  riastrad #  undef	__iomem
    341   1.4  riastrad #endif
    342   1.1  riastrad 
    343   1.1  riastrad static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
    344   1.1  riastrad 	.fb_probe = intelfb_create,
    345   1.1  riastrad };
    346   1.1  riastrad 
    347   1.1  riastrad static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
    348   1.1  riastrad {
    349   1.1  riastrad 	/* We rely on the object-free to release the VMA pinning for
    350   1.1  riastrad 	 * the info->screen_base mmaping. Leaking the VMA is simpler than
    351   1.1  riastrad 	 * trying to rectify all the possible error paths leading here.
    352   1.1  riastrad 	 */
    353   1.1  riastrad 
    354   1.1  riastrad 	drm_fb_helper_fini(&ifbdev->helper);
    355   1.1  riastrad 
    356   1.1  riastrad 	if (ifbdev->vma)
    357   1.1  riastrad 		intel_unpin_fb_vma(ifbdev->vma, ifbdev->vma_flags);
    358   1.1  riastrad 
    359   1.1  riastrad 	if (ifbdev->fb)
    360   1.1  riastrad 		drm_framebuffer_remove(&ifbdev->fb->base);
    361   1.1  riastrad 
    362   1.9  riastrad 	mutex_destroy(&ifbdev->hpd_lock);
    363   1.9  riastrad 
    364   1.1  riastrad 	kfree(ifbdev);
    365   1.1  riastrad }
    366   1.1  riastrad 
    367   1.1  riastrad /*
    368   1.1  riastrad  * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
    369   1.1  riastrad  * The core display code will have read out the current plane configuration,
    370   1.1  riastrad  * so we use that to figure out if there's an object for us to use as the
    371   1.1  riastrad  * fb, and if so, we re-use it for the fbdev configuration.
    372   1.1  riastrad  *
    373   1.1  riastrad  * Note we only support a single fb shared across pipes for boot (mostly for
    374   1.1  riastrad  * fbcon), so we just find the biggest and use that.
    375   1.1  riastrad  */
    376   1.1  riastrad static bool intel_fbdev_init_bios(struct drm_device *dev,
    377   1.1  riastrad 				 struct intel_fbdev *ifbdev)
    378   1.1  riastrad {
    379   1.1  riastrad 	struct intel_framebuffer *fb = NULL;
    380   1.1  riastrad 	struct drm_crtc *crtc;
    381   1.1  riastrad 	struct intel_crtc *intel_crtc;
    382   1.1  riastrad 	unsigned int max_size = 0;
    383   1.1  riastrad 
    384   1.1  riastrad 	/* Find the largest fb */
    385   1.1  riastrad 	for_each_crtc(dev, crtc) {
    386   1.1  riastrad 		struct drm_i915_gem_object *obj =
    387   1.1  riastrad 			intel_fb_obj(crtc->primary->state->fb);
    388   1.1  riastrad 		intel_crtc = to_intel_crtc(crtc);
    389   1.1  riastrad 
    390   1.1  riastrad 		if (!crtc->state->active || !obj) {
    391   1.1  riastrad 			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
    392   1.1  riastrad 				      pipe_name(intel_crtc->pipe));
    393   1.1  riastrad 			continue;
    394   1.1  riastrad 		}
    395   1.1  riastrad 
    396   1.1  riastrad 		if (obj->base.size > max_size) {
    397   1.1  riastrad 			DRM_DEBUG_KMS("found possible fb from plane %c\n",
    398   1.1  riastrad 				      pipe_name(intel_crtc->pipe));
    399   1.1  riastrad 			fb = to_intel_framebuffer(crtc->primary->state->fb);
    400   1.1  riastrad 			max_size = obj->base.size;
    401   1.1  riastrad 		}
    402   1.1  riastrad 	}
    403   1.1  riastrad 
    404   1.1  riastrad 	if (!fb) {
    405   1.1  riastrad 		DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n");
    406   1.1  riastrad 		goto out;
    407   1.1  riastrad 	}
    408   1.1  riastrad 
    409   1.1  riastrad 	/* Now make sure all the pipes will fit into it */
    410   1.1  riastrad 	for_each_crtc(dev, crtc) {
    411   1.1  riastrad 		unsigned int cur_size;
    412   1.1  riastrad 
    413   1.1  riastrad 		intel_crtc = to_intel_crtc(crtc);
    414   1.1  riastrad 
    415   1.1  riastrad 		if (!crtc->state->active) {
    416   1.1  riastrad 			DRM_DEBUG_KMS("pipe %c not active, skipping\n",
    417   1.1  riastrad 				      pipe_name(intel_crtc->pipe));
    418   1.1  riastrad 			continue;
    419   1.1  riastrad 		}
    420   1.1  riastrad 
    421   1.1  riastrad 		DRM_DEBUG_KMS("checking plane %c for BIOS fb\n",
    422   1.1  riastrad 			      pipe_name(intel_crtc->pipe));
    423   1.1  riastrad 
    424   1.1  riastrad 		/*
    425   1.1  riastrad 		 * See if the plane fb we found above will fit on this
    426   1.1  riastrad 		 * pipe.  Note we need to use the selected fb's pitch and bpp
    427   1.1  riastrad 		 * rather than the current pipe's, since they differ.
    428   1.1  riastrad 		 */
    429   1.1  riastrad 		cur_size = crtc->state->adjusted_mode.crtc_hdisplay;
    430   1.1  riastrad 		cur_size = cur_size * fb->base.format->cpp[0];
    431   1.1  riastrad 		if (fb->base.pitches[0] < cur_size) {
    432   1.1  riastrad 			DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
    433   1.1  riastrad 				      pipe_name(intel_crtc->pipe),
    434   1.1  riastrad 				      cur_size, fb->base.pitches[0]);
    435   1.1  riastrad 			fb = NULL;
    436   1.1  riastrad 			break;
    437   1.1  riastrad 		}
    438   1.1  riastrad 
    439   1.1  riastrad 		cur_size = crtc->state->adjusted_mode.crtc_vdisplay;
    440   1.1  riastrad 		cur_size = intel_fb_align_height(&fb->base, 0, cur_size);
    441   1.1  riastrad 		cur_size *= fb->base.pitches[0];
    442   1.1  riastrad 		DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
    443   1.1  riastrad 			      pipe_name(intel_crtc->pipe),
    444   1.1  riastrad 			      crtc->state->adjusted_mode.crtc_hdisplay,
    445   1.1  riastrad 			      crtc->state->adjusted_mode.crtc_vdisplay,
    446   1.1  riastrad 			      fb->base.format->cpp[0] * 8,
    447   1.1  riastrad 			      cur_size);
    448   1.1  riastrad 
    449   1.1  riastrad 		if (cur_size > max_size) {
    450   1.1  riastrad 			DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
    451   1.1  riastrad 				      pipe_name(intel_crtc->pipe),
    452   1.1  riastrad 				      cur_size, max_size);
    453   1.1  riastrad 			fb = NULL;
    454   1.1  riastrad 			break;
    455   1.1  riastrad 		}
    456   1.1  riastrad 
    457   1.1  riastrad 		DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n",
    458   1.1  riastrad 			      pipe_name(intel_crtc->pipe),
    459   1.1  riastrad 			      max_size, cur_size);
    460   1.1  riastrad 	}
    461   1.1  riastrad 
    462   1.1  riastrad 	if (!fb) {
    463   1.1  riastrad 		DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
    464   1.1  riastrad 		goto out;
    465   1.1  riastrad 	}
    466   1.1  riastrad 
    467   1.1  riastrad 	ifbdev->preferred_bpp = fb->base.format->cpp[0] * 8;
    468   1.1  riastrad 	ifbdev->fb = fb;
    469   1.1  riastrad 
    470   1.1  riastrad 	drm_framebuffer_get(&ifbdev->fb->base);
    471   1.1  riastrad 
    472   1.1  riastrad 	/* Final pass to check if any active pipes don't have fbs */
    473   1.1  riastrad 	for_each_crtc(dev, crtc) {
    474   1.1  riastrad 		intel_crtc = to_intel_crtc(crtc);
    475   1.1  riastrad 
    476   1.1  riastrad 		if (!crtc->state->active)
    477   1.1  riastrad 			continue;
    478   1.1  riastrad 
    479   1.1  riastrad 		WARN(!crtc->primary->state->fb,
    480   1.1  riastrad 		     "re-used BIOS config but lost an fb on crtc %d\n",
    481   1.1  riastrad 		     crtc->base.id);
    482   1.1  riastrad 	}
    483   1.1  riastrad 
    484   1.1  riastrad 
    485   1.1  riastrad 	DRM_DEBUG_KMS("using BIOS fb for initial console\n");
    486   1.1  riastrad 	return true;
    487   1.1  riastrad 
    488   1.1  riastrad out:
    489   1.1  riastrad 
    490   1.1  riastrad 	return false;
    491   1.1  riastrad }
    492   1.1  riastrad 
    493   1.1  riastrad static void intel_fbdev_suspend_worker(struct work_struct *work)
    494   1.1  riastrad {
    495   1.2  riastrad #ifndef __NetBSD__		/* XXX fb suspend */
    496   1.1  riastrad 	intel_fbdev_set_suspend(&container_of(work,
    497   1.1  riastrad 					      struct drm_i915_private,
    498   1.1  riastrad 					      fbdev_suspend_work)->drm,
    499   1.1  riastrad 				FBINFO_STATE_RUNNING,
    500   1.1  riastrad 				true);
    501   1.2  riastrad #endif
    502   1.1  riastrad }
    503   1.1  riastrad 
    504   1.1  riastrad int intel_fbdev_init(struct drm_device *dev)
    505   1.1  riastrad {
    506   1.1  riastrad 	struct drm_i915_private *dev_priv = to_i915(dev);
    507   1.1  riastrad 	struct intel_fbdev *ifbdev;
    508   1.1  riastrad 	int ret;
    509   1.1  riastrad 
    510   1.1  riastrad 	if (WARN_ON(!HAS_DISPLAY(dev_priv) || !INTEL_DISPLAY_ENABLED(dev_priv)))
    511   1.1  riastrad 		return -ENODEV;
    512   1.1  riastrad 
    513   1.1  riastrad 	ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
    514   1.1  riastrad 	if (ifbdev == NULL)
    515   1.1  riastrad 		return -ENOMEM;
    516   1.1  riastrad 
    517   1.1  riastrad 	mutex_init(&ifbdev->hpd_lock);
    518   1.1  riastrad 	drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs);
    519   1.1  riastrad 
    520   1.1  riastrad 	if (!intel_fbdev_init_bios(dev, ifbdev))
    521   1.1  riastrad 		ifbdev->preferred_bpp = 32;
    522   1.1  riastrad 
    523   1.1  riastrad 	ret = drm_fb_helper_init(dev, &ifbdev->helper, 4);
    524   1.1  riastrad 	if (ret) {
    525   1.1  riastrad 		kfree(ifbdev);
    526   1.1  riastrad 		return ret;
    527   1.1  riastrad 	}
    528   1.1  riastrad 
    529   1.1  riastrad 	dev_priv->fbdev = ifbdev;
    530   1.1  riastrad 	INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);
    531   1.1  riastrad 
    532   1.1  riastrad 	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
    533   1.1  riastrad 
    534   1.1  riastrad 	return 0;
    535   1.1  riastrad }
    536   1.1  riastrad 
    537   1.1  riastrad static void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
    538   1.1  riastrad {
    539   1.1  riastrad 	struct intel_fbdev *ifbdev = data;
    540   1.1  riastrad 
    541   1.1  riastrad 	/* Due to peculiar init order wrt to hpd handling this is separate. */
    542   1.1  riastrad 	if (drm_fb_helper_initial_config(&ifbdev->helper,
    543   1.1  riastrad 					 ifbdev->preferred_bpp))
    544   1.1  riastrad 		intel_fbdev_unregister(to_i915(ifbdev->helper.dev));
    545   1.1  riastrad }
    546   1.1  riastrad 
    547   1.1  riastrad void intel_fbdev_initial_config_async(struct drm_device *dev)
    548   1.1  riastrad {
    549   1.1  riastrad 	struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
    550   1.1  riastrad 
    551   1.1  riastrad 	if (!ifbdev)
    552   1.1  riastrad 		return;
    553   1.1  riastrad 
    554   1.1  riastrad 	ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev);
    555   1.1  riastrad }
    556   1.1  riastrad 
    557   1.1  riastrad static void intel_fbdev_sync(struct intel_fbdev *ifbdev)
    558   1.1  riastrad {
    559   1.1  riastrad 	if (!ifbdev->cookie)
    560   1.1  riastrad 		return;
    561   1.1  riastrad 
    562   1.1  riastrad 	/* Only serialises with all preceding async calls, hence +1 */
    563   1.1  riastrad 	async_synchronize_cookie(ifbdev->cookie + 1);
    564   1.1  riastrad 	ifbdev->cookie = 0;
    565   1.1  riastrad }
    566   1.1  riastrad 
    567   1.1  riastrad void intel_fbdev_unregister(struct drm_i915_private *dev_priv)
    568   1.1  riastrad {
    569   1.1  riastrad 	struct intel_fbdev *ifbdev = dev_priv->fbdev;
    570   1.1  riastrad 
    571   1.1  riastrad 	if (!ifbdev)
    572   1.1  riastrad 		return;
    573   1.1  riastrad 
    574   1.1  riastrad 	cancel_work_sync(&dev_priv->fbdev_suspend_work);
    575   1.7  riastrad #ifndef __NetBSD__		/* XXX fb async */
    576   1.1  riastrad 	if (!current_is_async())
    577   1.7  riastrad #endif
    578   1.1  riastrad 		intel_fbdev_sync(ifbdev);
    579   1.1  riastrad 
    580   1.1  riastrad 	drm_fb_helper_unregister_fbi(&ifbdev->helper);
    581   1.1  riastrad }
    582   1.1  riastrad 
    583   1.1  riastrad void intel_fbdev_fini(struct drm_i915_private *dev_priv)
    584   1.1  riastrad {
    585   1.1  riastrad 	struct intel_fbdev *ifbdev = fetch_and_zero(&dev_priv->fbdev);
    586   1.1  riastrad 
    587   1.1  riastrad 	if (!ifbdev)
    588   1.1  riastrad 		return;
    589   1.1  riastrad 
    590   1.1  riastrad 	intel_fbdev_destroy(ifbdev);
    591   1.1  riastrad }
    592   1.1  riastrad 
    593   1.1  riastrad /* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD
    594   1.1  riastrad  * processing, fbdev will perform a full connector reprobe if a hotplug event
    595   1.1  riastrad  * was received while HPD was suspended.
    596   1.1  riastrad  */
    597   1.8  riastrad #ifndef __NetBSD__		/* XXX fb suspend */
    598   1.1  riastrad static void intel_fbdev_hpd_set_suspend(struct intel_fbdev *ifbdev, int state)
    599   1.1  riastrad {
    600   1.1  riastrad 	bool send_hpd = false;
    601   1.1  riastrad 
    602   1.1  riastrad 	mutex_lock(&ifbdev->hpd_lock);
    603   1.1  riastrad 	ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED;
    604   1.1  riastrad 	send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting;
    605   1.1  riastrad 	ifbdev->hpd_waiting = false;
    606   1.1  riastrad 	mutex_unlock(&ifbdev->hpd_lock);
    607   1.1  riastrad 
    608   1.1  riastrad 	if (send_hpd) {
    609   1.1  riastrad 		DRM_DEBUG_KMS("Handling delayed fbcon HPD event\n");
    610   1.1  riastrad 		drm_fb_helper_hotplug_event(&ifbdev->helper);
    611   1.1  riastrad 	}
    612   1.1  riastrad }
    613   1.8  riastrad #endif	/* __NetBSD__ */
    614   1.1  riastrad 
    615   1.1  riastrad void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
    616   1.1  riastrad {
    617   1.2  riastrad #ifndef __NetBSD__		/* XXX fb suspend */
    618   1.1  riastrad 	struct drm_i915_private *dev_priv = to_i915(dev);
    619   1.1  riastrad 	struct intel_fbdev *ifbdev = dev_priv->fbdev;
    620   1.1  riastrad 	struct fb_info *info;
    621   1.1  riastrad 
    622   1.1  riastrad 	if (!ifbdev || !ifbdev->vma)
    623   1.1  riastrad 		return;
    624   1.1  riastrad 
    625   1.1  riastrad 	info = ifbdev->helper.fbdev;
    626   1.1  riastrad 
    627   1.1  riastrad 	if (synchronous) {
    628   1.1  riastrad 		/* Flush any pending work to turn the console on, and then
    629   1.1  riastrad 		 * wait to turn it off. It must be synchronous as we are
    630   1.1  riastrad 		 * about to suspend or unload the driver.
    631   1.1  riastrad 		 *
    632   1.1  riastrad 		 * Note that from within the work-handler, we cannot flush
    633   1.1  riastrad 		 * ourselves, so only flush outstanding work upon suspend!
    634   1.1  riastrad 		 */
    635   1.1  riastrad 		if (state != FBINFO_STATE_RUNNING)
    636   1.1  riastrad 			flush_work(&dev_priv->fbdev_suspend_work);
    637   1.1  riastrad 
    638   1.1  riastrad 		console_lock();
    639   1.1  riastrad 	} else {
    640   1.1  riastrad 		/*
    641   1.1  riastrad 		 * The console lock can be pretty contented on resume due
    642   1.1  riastrad 		 * to all the printk activity.  Try to keep it out of the hot
    643   1.1  riastrad 		 * path of resume if possible.
    644   1.1  riastrad 		 */
    645   1.1  riastrad 		WARN_ON(state != FBINFO_STATE_RUNNING);
    646   1.1  riastrad 		if (!console_trylock()) {
    647   1.1  riastrad 			/* Don't block our own workqueue as this can
    648   1.1  riastrad 			 * be run in parallel with other i915.ko tasks.
    649   1.1  riastrad 			 */
    650   1.1  riastrad 			schedule_work(&dev_priv->fbdev_suspend_work);
    651   1.1  riastrad 			return;
    652   1.1  riastrad 		}
    653   1.1  riastrad 	}
    654   1.1  riastrad 
    655   1.1  riastrad 	/* On resume from hibernation: If the object is shmemfs backed, it has
    656   1.1  riastrad 	 * been restored from swap. If the object is stolen however, it will be
    657   1.1  riastrad 	 * full of whatever garbage was left in there.
    658   1.1  riastrad 	 */
    659   1.1  riastrad 	if (state == FBINFO_STATE_RUNNING &&
    660   1.1  riastrad 	    intel_fb_obj(&ifbdev->fb->base)->stolen)
    661   1.1  riastrad 		memset_io(info->screen_base, 0, info->screen_size);
    662   1.1  riastrad 
    663   1.1  riastrad 	drm_fb_helper_set_suspend(&ifbdev->helper, state);
    664   1.1  riastrad 	console_unlock();
    665   1.1  riastrad 
    666   1.1  riastrad 	intel_fbdev_hpd_set_suspend(ifbdev, state);
    667   1.2  riastrad #endif
    668   1.1  riastrad }
    669   1.1  riastrad 
    670   1.1  riastrad void intel_fbdev_output_poll_changed(struct drm_device *dev)
    671   1.1  riastrad {
    672   1.1  riastrad 	struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
    673   1.1  riastrad 	bool send_hpd;
    674   1.1  riastrad 
    675   1.1  riastrad 	if (!ifbdev)
    676   1.1  riastrad 		return;
    677   1.1  riastrad 
    678   1.1  riastrad 	intel_fbdev_sync(ifbdev);
    679   1.1  riastrad 
    680   1.1  riastrad 	mutex_lock(&ifbdev->hpd_lock);
    681   1.1  riastrad 	send_hpd = !ifbdev->hpd_suspended;
    682   1.1  riastrad 	ifbdev->hpd_waiting = true;
    683   1.1  riastrad 	mutex_unlock(&ifbdev->hpd_lock);
    684   1.1  riastrad 
    685   1.1  riastrad 	if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup))
    686   1.1  riastrad 		drm_fb_helper_hotplug_event(&ifbdev->helper);
    687   1.1  riastrad }
    688   1.1  riastrad 
    689   1.1  riastrad void intel_fbdev_restore_mode(struct drm_device *dev)
    690   1.1  riastrad {
    691   1.1  riastrad 	struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
    692   1.1  riastrad 
    693   1.1  riastrad 	if (!ifbdev)
    694   1.1  riastrad 		return;
    695   1.1  riastrad 
    696   1.1  riastrad 	intel_fbdev_sync(ifbdev);
    697   1.1  riastrad 	if (!ifbdev->vma)
    698   1.1  riastrad 		return;
    699   1.1  riastrad 
    700   1.1  riastrad 	if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0)
    701   1.1  riastrad 		intel_fbdev_invalidate(ifbdev);
    702   1.1  riastrad }
    703