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