intel_fbdev.c 22.6 KB
Newer Older
J
Jesse Barnes 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright © 2007 David Airlie
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *     David Airlie
 */

27
#include <linux/async.h>
J
Jesse Barnes 已提交
28 29
#include <linux/module.h>
#include <linux/kernel.h>
30
#include <linux/console.h>
J
Jesse Barnes 已提交
31 32 33 34 35 36 37 38
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
39
#include <linux/vga_switcheroo.h>
J
Jesse Barnes 已提交
40

41 42 43
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
J
Jesse Barnes 已提交
44
#include "intel_drv.h"
45
#include <drm/i915_drm.h>
J
Jesse Barnes 已提交
46 47
#include "i915_drv.h"

48 49 50 51 52 53 54 55 56 57 58
static int intel_fbdev_set_par(struct fb_info *info)
{
	struct drm_fb_helper *fb_helper = info->par;
	struct intel_fbdev *ifbdev =
		container_of(fb_helper, struct intel_fbdev, helper);
	int ret;

	ret = drm_fb_helper_set_par(info);

	if (ret == 0) {
		mutex_lock(&fb_helper->dev->struct_mutex);
59
		intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
60 61 62 63 64 65
		mutex_unlock(&fb_helper->dev->struct_mutex);
	}

	return ret;
}

66 67 68 69 70 71 72 73 74 75 76
static int intel_fbdev_blank(int blank, struct fb_info *info)
{
	struct drm_fb_helper *fb_helper = info->par;
	struct intel_fbdev *ifbdev =
		container_of(fb_helper, struct intel_fbdev, helper);
	int ret;

	ret = drm_fb_helper_blank(blank, info);

	if (ret == 0) {
		mutex_lock(&fb_helper->dev->struct_mutex);
77
		intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
78 79 80 81 82 83
		mutex_unlock(&fb_helper->dev->struct_mutex);
	}

	return ret;
}

84 85 86 87 88 89 90 91 92 93 94 95
static int intel_fbdev_pan_display(struct fb_var_screeninfo *var,
				   struct fb_info *info)
{
	struct drm_fb_helper *fb_helper = info->par;
	struct intel_fbdev *ifbdev =
		container_of(fb_helper, struct intel_fbdev, helper);

	int ret;
	ret = drm_fb_helper_pan_display(var, info);

	if (ret == 0) {
		mutex_lock(&fb_helper->dev->struct_mutex);
96
		intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
97 98 99 100 101 102
		mutex_unlock(&fb_helper->dev->struct_mutex);
	}

	return ret;
}

J
Jesse Barnes 已提交
103 104
static struct fb_ops intelfb_ops = {
	.owner = THIS_MODULE,
105
	.fb_check_var = drm_fb_helper_check_var,
106
	.fb_set_par = intel_fbdev_set_par,
107 108 109
	.fb_fillrect = drm_fb_helper_cfb_fillrect,
	.fb_copyarea = drm_fb_helper_cfb_copyarea,
	.fb_imageblit = drm_fb_helper_cfb_imageblit,
110
	.fb_pan_display = intel_fbdev_pan_display,
111
	.fb_blank = intel_fbdev_blank,
112
	.fb_setcmap = drm_fb_helper_setcmap,
J
Jesse Barnes 已提交
113 114
	.fb_debug_enter = drm_fb_helper_debug_enter,
	.fb_debug_leave = drm_fb_helper_debug_leave,
J
Jesse Barnes 已提交
115 116
};

117 118
static int intelfb_alloc(struct drm_fb_helper *helper,
			 struct drm_fb_helper_surface_size *sizes)
J
Jesse Barnes 已提交
119
{
120 121
	struct intel_fbdev *ifbdev =
		container_of(helper, struct intel_fbdev, helper);
122
	struct drm_framebuffer *fb;
123
	struct drm_device *dev = helper->dev;
124
	struct drm_i915_private *dev_priv = to_i915(dev);
125
	struct drm_mode_fb_cmd2 mode_cmd = {};
126
	struct drm_i915_gem_object *obj = NULL;
127
	int size, ret;
J
Jesse Barnes 已提交
128

129
	/* we don't do packed 24bpp */
130 131
	if (sizes->surface_bpp == 24)
		sizes->surface_bpp = 32;
132

133 134
	mode_cmd.width = sizes->surface_width;
	mode_cmd.height = sizes->surface_height;
J
Jesse Barnes 已提交
135

136 137
	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
				    DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
138 139
	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
							  sizes->surface_depth);
J
Jesse Barnes 已提交
140

141
	size = mode_cmd.pitches[0] * mode_cmd.height;
142
	size = PAGE_ALIGN(size);
143 144 145 146 147 148

	/* If the FB is too big, just don't use it since fbdev is not very
	 * important and we should probably use that space with FBC or other
	 * features. */
	if (size * 2 < dev_priv->gtt.stolen_usable_size)
		obj = i915_gem_object_create_stolen(dev, size);
149 150
	if (obj == NULL)
		obj = i915_gem_alloc_object(dev, size);
151
	if (!obj) {
152
		DRM_ERROR("failed to allocate framebuffer\n");
J
Jesse Barnes 已提交
153 154 155 156
		ret = -ENOMEM;
		goto out;
	}

157 158 159
	fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
	if (IS_ERR(fb)) {
		ret = PTR_ERR(fb);
160 161 162 163
		goto out_unref;
	}

	/* Flush everything out, we'll be doing GTT only from now on */
164
	ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL, NULL);
165 166 167
	if (ret) {
		DRM_ERROR("failed to pin obj: %d\n", ret);
		goto out_fb;
168 169 170
	}

	ifbdev->fb = to_intel_framebuffer(fb);
171 172 173

	return 0;

174 175
out_fb:
	drm_framebuffer_remove(fb);
176 177 178 179 180 181 182 183 184 185 186
out_unref:
	drm_gem_object_unreference(&obj->base);
out:
	return ret;
}

static int intelfb_create(struct drm_fb_helper *helper,
			  struct drm_fb_helper_surface_size *sizes)
{
	struct intel_fbdev *ifbdev =
		container_of(helper, struct intel_fbdev, helper);
187
	struct intel_framebuffer *intel_fb = ifbdev->fb;
188 189 190 191 192 193
	struct drm_device *dev = helper->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct fb_info *info;
	struct drm_framebuffer *fb;
	struct drm_i915_gem_object *obj;
	int size, ret;
194
	bool prealloc = false;
195 196 197

	mutex_lock(&dev->struct_mutex);

198 199 200 201 202 203 204 205 206 207
	if (intel_fb &&
	    (sizes->fb_width > intel_fb->base.width ||
	     sizes->fb_height > intel_fb->base.height)) {
		DRM_DEBUG_KMS("BIOS fb too small (%dx%d), we require (%dx%d),"
			      " releasing it\n",
			      intel_fb->base.width, intel_fb->base.height,
			      sizes->fb_width, sizes->fb_height);
		drm_framebuffer_unreference(&intel_fb->base);
		intel_fb = ifbdev->fb = NULL;
	}
208
	if (!intel_fb || WARN_ON(!intel_fb->obj)) {
209
		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
210 211 212
		ret = intelfb_alloc(helper, sizes);
		if (ret)
			goto out_unlock;
213
		intel_fb = ifbdev->fb;
214
	} else {
215
		DRM_DEBUG_KMS("re-using BIOS fb\n");
216
		prealloc = true;
217 218 219 220 221 222 223
		sizes->fb_width = intel_fb->base.width;
		sizes->fb_height = intel_fb->base.height;
	}

	obj = intel_fb->obj;
	size = obj->base.size;

224 225 226
	info = drm_fb_helper_alloc_fbi(helper);
	if (IS_ERR(info)) {
		ret = PTR_ERR(info);
227
		goto out_unpin;
J
Jesse Barnes 已提交
228 229
	}

230
	info->par = helper;
J
Jesse Barnes 已提交
231

232
	fb = &ifbdev->fb->base;
J
Jesse Barnes 已提交
233

234
	ifbdev->helper.fb = fb;
235

J
Jesse Barnes 已提交
236 237
	strcpy(info->fix.id, "inteldrmfb");

238
	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
J
Jesse Barnes 已提交
239 240
	info->fbops = &intelfb_ops;

241
	/* setup aperture base/size for vesafb takeover */
242
	info->apertures->ranges[0].base = dev->mode_config.fb_base;
243
	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
244

245
	info->fix.smem_start = dev->mode_config.fb_base + i915_gem_obj_ggtt_offset(obj);
J
Jesse Barnes 已提交
246 247
	info->fix.smem_len = size;

248
	info->screen_base =
249
		ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
250
			   size);
J
Jesse Barnes 已提交
251 252
	if (!info->screen_base) {
		ret = -ENOSPC;
253
		goto out_destroy_fbi;
J
Jesse Barnes 已提交
254 255 256
	}
	info->screen_size = size;

257 258 259
	/* This driver doesn't need a VT switch to restore the mode on resume */
	info->skip_vt_switch = true;

260
	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
261
	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
J
Jesse Barnes 已提交
262

263 264 265 266
	/* If the object is shmemfs backed, it will have given us zeroed pages.
	 * If the object is stolen however, it will be full of whatever
	 * garbage was left in there.
	 */
267
	if (ifbdev->fb->obj->stolen && !prealloc)
268 269
		memset_io(info->screen_base, 0, info->screen_size);

270
	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
J
Jesse Barnes 已提交
271

272
	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08llx, bo %p\n",
273
		      fb->width, fb->height,
274
		      i915_gem_obj_ggtt_offset(obj), obj);
J
Jesse Barnes 已提交
275 276

	mutex_unlock(&dev->struct_mutex);
277
	vga_switcheroo_client_fb_set(dev->pdev, info);
J
Jesse Barnes 已提交
278 279
	return 0;

280 281
out_destroy_fbi:
	drm_fb_helper_release_fbi(helper);
282
out_unpin:
B
Ben Widawsky 已提交
283
	i915_gem_object_ggtt_unpin(obj);
284
	drm_gem_object_unreference(&obj->base);
285
out_unlock:
J
Jesse Barnes 已提交
286 287 288 289
	mutex_unlock(&dev->struct_mutex);
	return ret;
}

290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
/** Sets the color ramps on behalf of RandR */
static void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
				    u16 blue, int regno)
{
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);

	intel_crtc->lut_r[regno] = red >> 8;
	intel_crtc->lut_g[regno] = green >> 8;
	intel_crtc->lut_b[regno] = blue >> 8;
}

static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
				    u16 *blue, int regno)
{
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);

	*red = intel_crtc->lut_r[regno] << 8;
	*green = intel_crtc->lut_g[regno] << 8;
	*blue = intel_crtc->lut_b[regno] << 8;
}

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
static struct drm_fb_helper_crtc *
intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
{
	int i;

	for (i = 0; i < fb_helper->crtc_count; i++)
		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
			return &fb_helper->crtc_info[i];

	return NULL;
}

/*
 * Try to read the BIOS display configuration and use it for the initial
 * fb configuration.
 *
 * The BIOS or boot loader will generally create an initial display
 * configuration for us that includes some set of active pipes and displays.
 * This routine tries to figure out which pipes and connectors are active
 * and stuffs them into the crtcs and modes array given to us by the
 * drm_fb_helper code.
 *
 * The overall sequence is:
 *   intel_fbdev_init - from driver load
 *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
 *     drm_fb_helper_init - build fb helper structs
 *     drm_fb_helper_single_add_all_connectors - more fb helper structs
 *   intel_fbdev_initial_config - apply the config
 *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
 *         drm_setup_crtcs - build crtc config for fbdev
 *           intel_fb_initial_config - find active connectors etc
 *         drm_fb_helper_single_fb_probe - set up fbdev
 *           intelfb_create - re-use or alloc fb, build out fbdev structs
 *
 * Note that we don't make special consideration whether we could actually
 * switch to the selected modes without a full modeset. E.g. when the display
 * is in VGA mode we need to recalculate watermarks and set a new high-res
 * framebuffer anyway.
 */
static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
				    struct drm_fb_helper_crtc **crtcs,
				    struct drm_display_mode **modes,
353
				    struct drm_fb_offset *offsets,
354 355
				    bool *enabled, int width, int height)
{
356
	struct drm_device *dev = fb_helper->dev;
357
	int i, j;
358
	bool *save_enabled;
359
	bool fallback = true;
360 361
	int num_connectors_enabled = 0;
	int num_connectors_detected = 0;
362 363
	uint64_t conn_configured = 0, mask;
	int pass = 0;
364 365 366 367 368 369 370

	save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
			       GFP_KERNEL);
	if (!save_enabled)
		return false;

	memcpy(save_enabled, enabled, dev->mode_config.num_connector);
371 372
	mask = (1 << fb_helper->connector_count) - 1;
retry:
373 374 375 376 377 378 379 380
	for (i = 0; i < fb_helper->connector_count; i++) {
		struct drm_fb_helper_connector *fb_conn;
		struct drm_connector *connector;
		struct drm_encoder *encoder;
		struct drm_fb_helper_crtc *new_crtc;

		fb_conn = fb_helper->connector_info[i];
		connector = fb_conn->connector;
381

382 383 384 385 386 387
		if (conn_configured & (1 << i))
			continue;

		if (pass == 0 && !connector->has_tile)
			continue;

388 389 390
		if (connector->status == connector_status_connected)
			num_connectors_detected++;

391
		if (!enabled[i]) {
392
			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
393
				      connector->name);
394
			conn_configured |= (1 << i);
395 396 397
			continue;
		}

398 399 400 401 402 403 404
		if (connector->force == DRM_FORCE_OFF) {
			DRM_DEBUG_KMS("connector %s is disabled by user, skipping\n",
				      connector->name);
			enabled[i] = false;
			continue;
		}

405 406
		encoder = connector->encoder;
		if (!encoder || WARN_ON(!encoder->crtc)) {
407 408 409
			if (connector->force > DRM_FORCE_OFF)
				goto bail;

410
			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
411
				      connector->name);
412
			enabled[i] = false;
413
			conn_configured |= (1 << i);
414 415 416
			continue;
		}

417 418
		num_connectors_enabled++;

419 420 421 422 423 424 425 426
		new_crtc = intel_fb_helper_crtc(fb_helper, encoder->crtc);

		/*
		 * Make sure we're not trying to drive multiple connectors
		 * with a single CRTC, since our cloning support may not
		 * match the BIOS.
		 */
		for (j = 0; j < fb_helper->connector_count; j++) {
427
			if (crtcs[j] == new_crtc) {
428
				DRM_DEBUG_KMS("fallback: cloned configuration\n");
429
				goto bail;
430
			}
431 432
		}

433
		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
434
			      connector->name);
435 436 437 438 439 440

		/* go for command line mode first */
		modes[i] = drm_pick_cmdline_mode(fb_conn, width, height);

		/* try for preferred next */
		if (!modes[i]) {
441 442
			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
				      connector->name, connector->has_tile);
443 444 445 446
			modes[i] = drm_has_preferred_mode(fb_conn, width,
							  height);
		}

447 448 449
		/* No preferred mode marked by the EDID? Are there any modes? */
		if (!modes[i] && !list_empty(&connector->modes)) {
			DRM_DEBUG_KMS("using first mode listed on connector %s\n",
450
				      connector->name);
451 452 453 454 455
			modes[i] = list_first_entry(&connector->modes,
						    struct drm_display_mode,
						    head);
		}

456 457 458 459 460 461
		/* last resort: use current mode */
		if (!modes[i]) {
			/*
			 * IMPORTANT: We want to use the adjusted mode (i.e.
			 * after the panel fitter upscaling) as the initial
			 * config, not the input mode, which is what crtc->mode
462
			 * usually contains. But since our current
463
			 * code puts a mode derived from the post-pfit timings
464
			 * into crtc->mode this works out correctly.
465
			 */
466
			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
467
				      connector->name);
468
			modes[i] = &encoder->crtc->mode;
469 470 471
		}
		crtcs[i] = new_crtc;

472
		DRM_DEBUG_KMS("connector %s on pipe %c [CRTC:%d]: %dx%d%s\n",
473
			      connector->name,
474
			      pipe_name(to_intel_crtc(encoder->crtc)->pipe),
475
			      encoder->crtc->base.id,
476 477
			      modes[i]->hdisplay, modes[i]->vdisplay,
			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
478

479
		fallback = false;
480 481 482 483 484 485
		conn_configured |= (1 << i);
	}

	if ((conn_configured & mask) != mask) {
		pass++;
		goto retry;
486 487
	}

488 489 490 491 492 493 494 495 496 497 498 499 500
	/*
	 * If the BIOS didn't enable everything it could, fall back to have the
	 * same user experiencing of lighting up as much as possible like the
	 * fbdev helper library.
	 */
	if (num_connectors_enabled != num_connectors_detected &&
	    num_connectors_enabled < INTEL_INFO(dev)->num_pipes) {
		DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
		DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
			      num_connectors_detected);
		fallback = true;
	}

501
	if (fallback) {
502
bail:
503
		DRM_DEBUG_KMS("Not using firmware configuration\n");
504 505 506
		memcpy(enabled, save_enabled, dev->mode_config.num_connector);
		kfree(save_enabled);
		return false;
507 508
	}

509
	kfree(save_enabled);
510 511 512
	return true;
}

513
static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
514
	.initial_config = intel_fb_initial_config,
515 516
	.gamma_set = intel_crtc_fb_gamma_set,
	.gamma_get = intel_crtc_fb_gamma_get,
517
	.fb_probe = intelfb_create,
518
};
J
Jesse Barnes 已提交
519

520 521
static void intel_fbdev_destroy(struct drm_device *dev,
				struct intel_fbdev *ifbdev)
J
Jesse Barnes 已提交
522
{
523

524 525
	drm_fb_helper_unregister_fbi(&ifbdev->helper);
	drm_fb_helper_release_fbi(&ifbdev->helper);
J
Jesse Barnes 已提交
526

527
	drm_fb_helper_fini(&ifbdev->helper);
J
Jesse Barnes 已提交
528

529
	drm_framebuffer_unregister_private(&ifbdev->fb->base);
530
	drm_framebuffer_remove(&ifbdev->fb->base);
J
Jesse Barnes 已提交
531
}
532

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
/*
 * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
 * The core display code will have read out the current plane configuration,
 * so we use that to figure out if there's an object for us to use as the
 * fb, and if so, we re-use it for the fbdev configuration.
 *
 * Note we only support a single fb shared across pipes for boot (mostly for
 * fbcon), so we just find the biggest and use that.
 */
static bool intel_fbdev_init_bios(struct drm_device *dev,
				 struct intel_fbdev *ifbdev)
{
	struct intel_framebuffer *fb = NULL;
	struct drm_crtc *crtc;
	struct intel_crtc *intel_crtc;
	unsigned int max_size = 0;

	/* Find the largest fb */
551
	for_each_crtc(dev, crtc) {
552 553
		struct drm_i915_gem_object *obj =
			intel_fb_obj(crtc->primary->state->fb);
554 555
		intel_crtc = to_intel_crtc(crtc);

556
		if (!crtc->state->active || !obj) {
557 558 559 560 561
			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
				      pipe_name(intel_crtc->pipe));
			continue;
		}

562
		if (obj->base.size > max_size) {
563 564
			DRM_DEBUG_KMS("found possible fb from plane %c\n",
				      pipe_name(intel_crtc->pipe));
565 566
			fb = to_intel_framebuffer(crtc->primary->state->fb);
			max_size = obj->base.size;
567 568 569 570 571 572 573 574 575
		}
	}

	if (!fb) {
		DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n");
		goto out;
	}

	/* Now make sure all the pipes will fit into it */
576
	for_each_crtc(dev, crtc) {
577 578 579 580
		unsigned int cur_size;

		intel_crtc = to_intel_crtc(crtc);

581
		if (!crtc->state->active) {
582 583 584 585 586 587 588 589 590 591
			DRM_DEBUG_KMS("pipe %c not active, skipping\n",
				      pipe_name(intel_crtc->pipe));
			continue;
		}

		DRM_DEBUG_KMS("checking plane %c for BIOS fb\n",
			      pipe_name(intel_crtc->pipe));

		/*
		 * See if the plane fb we found above will fit on this
592 593
		 * pipe.  Note we need to use the selected fb's pitch and bpp
		 * rather than the current pipe's, since they differ.
594
		 */
595
		cur_size = intel_crtc->config->base.adjusted_mode.crtc_hdisplay;
596 597 598 599 600 601 602 603 604
		cur_size = cur_size * fb->base.bits_per_pixel / 8;
		if (fb->base.pitches[0] < cur_size) {
			DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
				      pipe_name(intel_crtc->pipe),
				      cur_size, fb->base.pitches[0]);
			fb = NULL;
			break;
		}

605
		cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
606
		cur_size = intel_fb_align_height(dev, cur_size,
607 608
						 fb->base.pixel_format,
						 fb->base.modifier[0]);
609 610 611
		cur_size *= fb->base.pitches[0];
		DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
			      pipe_name(intel_crtc->pipe),
612 613
			      intel_crtc->config->base.adjusted_mode.crtc_hdisplay,
			      intel_crtc->config->base.adjusted_mode.crtc_vdisplay,
614
			      fb->base.bits_per_pixel,
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
			      cur_size);

		if (cur_size > max_size) {
			DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
				      pipe_name(intel_crtc->pipe),
				      cur_size, max_size);
			fb = NULL;
			break;
		}

		DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n",
			      pipe_name(intel_crtc->pipe),
			      max_size, cur_size);
	}

	if (!fb) {
		DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
		goto out;
	}

635
	ifbdev->preferred_bpp = fb->base.bits_per_pixel;
636 637
	ifbdev->fb = fb;

638
	drm_framebuffer_reference(&ifbdev->fb->base);
639 640

	/* Final pass to check if any active pipes don't have fbs */
641
	for_each_crtc(dev, crtc) {
642 643
		intel_crtc = to_intel_crtc(crtc);

644
		if (!crtc->state->active)
645 646
			continue;

647
		WARN(!crtc->primary->fb,
648 649 650 651 652 653 654 655 656 657 658 659 660
		     "re-used BIOS config but lost an fb on crtc %d\n",
		     crtc->base.id);
	}


	DRM_DEBUG_KMS("using BIOS fb for initial console\n");
	return true;

out:

	return false;
}

661 662 663 664 665 666 667 668 669
static void intel_fbdev_suspend_worker(struct work_struct *work)
{
	intel_fbdev_set_suspend(container_of(work,
					     struct drm_i915_private,
					     fbdev_suspend_work)->dev,
				FBINFO_STATE_RUNNING,
				true);
}

670 671
int intel_fbdev_init(struct drm_device *dev)
{
672
	struct intel_fbdev *ifbdev;
673
	struct drm_i915_private *dev_priv = dev->dev_private;
674
	int ret;
675

676 677 678 679 680
	if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
		return -ENODEV;

	ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
	if (ifbdev == NULL)
681 682
		return -ENOMEM;

683 684
	drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs);

685 686
	if (!intel_fbdev_init_bios(dev, ifbdev))
		ifbdev->preferred_bpp = 32;
687

688
	ret = drm_fb_helper_init(dev, &ifbdev->helper,
689
				 INTEL_INFO(dev)->num_pipes, 4);
690 691 692 693
	if (ret) {
		kfree(ifbdev);
		return ret;
	}
694

R
Rob Clark 已提交
695 696
	ifbdev->helper.atomic = true;

697
	dev_priv->fbdev = ifbdev;
698 699
	INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);

700
	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
701

J
Jesse Barnes 已提交
702 703
	return 0;
}
704

705
void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
706
{
707
	struct drm_i915_private *dev_priv = data;
708
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
709 710

	/* Due to peculiar init order wrt to hpd handling this is separate. */
711
	drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
712 713
}

714 715
void intel_fbdev_fini(struct drm_device *dev)
{
716
	struct drm_i915_private *dev_priv = dev->dev_private;
717 718 719
	if (!dev_priv->fbdev)
		return;

720 721
	flush_work(&dev_priv->fbdev_suspend_work);

722
	async_synchronize_full();
723
	intel_fbdev_destroy(dev, dev_priv->fbdev);
724
	kfree(dev_priv->fbdev);
725 726
	dev_priv->fbdev = NULL;
}
727

728
void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
729
{
730
	struct drm_i915_private *dev_priv = dev->dev_private;
731 732 733 734
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
	struct fb_info *info;

	if (!ifbdev)
735 736
		return;

737 738
	info = ifbdev->helper.fbdev;

739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
	if (synchronous) {
		/* Flush any pending work to turn the console on, and then
		 * wait to turn it off. It must be synchronous as we are
		 * about to suspend or unload the driver.
		 *
		 * Note that from within the work-handler, we cannot flush
		 * ourselves, so only flush outstanding work upon suspend!
		 */
		if (state != FBINFO_STATE_RUNNING)
			flush_work(&dev_priv->fbdev_suspend_work);
		console_lock();
	} else {
		/*
		 * The console lock can be pretty contented on resume due
		 * to all the printk activity.  Try to keep it out of the hot
		 * path of resume if possible.
		 */
		WARN_ON(state != FBINFO_STATE_RUNNING);
		if (!console_trylock()) {
			/* Don't block our own workqueue as this can
			 * be run in parallel with other i915.ko tasks.
			 */
			schedule_work(&dev_priv->fbdev_suspend_work);
			return;
		}
	}

766 767 768 769
	/* On resume from hibernation: If the object is shmemfs backed, it has
	 * been restored from swap. If the object is stolen however, it will be
	 * full of whatever garbage was left in there.
	 */
770
	if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen)
771 772
		memset_io(info->screen_base, 0, info->screen_size);

773
	drm_fb_helper_set_suspend(&ifbdev->helper, state);
774
	console_unlock();
775 776
}

777
void intel_fbdev_output_poll_changed(struct drm_device *dev)
778
{
779
	struct drm_i915_private *dev_priv = dev->dev_private;
780 781
	if (dev_priv->fbdev)
		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
782
}
783

784
void intel_fbdev_restore_mode(struct drm_device *dev)
785 786
{
	int ret;
787
	struct drm_i915_private *dev_priv = dev->dev_private;
788 789
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
	struct drm_fb_helper *fb_helper;
790

791
	if (!ifbdev)
B
Ben Widawsky 已提交
792 793
		return;

794 795 796 797
	fb_helper = &ifbdev->helper;

	ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
	if (ret) {
798
		DRM_DEBUG("failed to restore crtc mode\n");
799 800 801 802 803
	} else {
		mutex_lock(&fb_helper->dev->struct_mutex);
		intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT);
		mutex_unlock(&fb_helper->dev->struct_mutex);
	}
804
}