intel_fbdev.c 19.4 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 27 28 29 30 31 32 33 34 35 36
/*
 * 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
 */

#include <linux/module.h>
#include <linux/kernel.h>
#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>
37
#include <linux/vga_switcheroo.h>
J
Jesse Barnes 已提交
38

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

static struct fb_ops intelfb_ops = {
	.owner = THIS_MODULE,
48 49
	.fb_check_var = drm_fb_helper_check_var,
	.fb_set_par = drm_fb_helper_set_par,
J
Jesse Barnes 已提交
50 51 52
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
53 54
	.fb_pan_display = drm_fb_helper_pan_display,
	.fb_blank = drm_fb_helper_blank,
55
	.fb_setcmap = drm_fb_helper_setcmap,
J
Jesse Barnes 已提交
56 57
	.fb_debug_enter = drm_fb_helper_debug_enter,
	.fb_debug_leave = drm_fb_helper_debug_leave,
J
Jesse Barnes 已提交
58 59
};

60 61
static int intelfb_alloc(struct drm_fb_helper *helper,
			 struct drm_fb_helper_surface_size *sizes)
J
Jesse Barnes 已提交
62
{
63 64
	struct intel_fbdev *ifbdev =
		container_of(helper, struct intel_fbdev, helper);
65
	struct drm_framebuffer *fb;
66
	struct drm_device *dev = helper->dev;
67
	struct drm_mode_fb_cmd2 mode_cmd = {};
68
	struct drm_i915_gem_object *obj;
69
	int size, ret;
J
Jesse Barnes 已提交
70

71
	/* we don't do packed 24bpp */
72 73
	if (sizes->surface_bpp == 24)
		sizes->surface_bpp = 32;
74

75 76
	mode_cmd.width = sizes->surface_width;
	mode_cmd.height = sizes->surface_height;
J
Jesse Barnes 已提交
77

78 79
	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
				    DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
80 81
	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
							  sizes->surface_depth);
J
Jesse Barnes 已提交
82

83
	size = mode_cmd.pitches[0] * mode_cmd.height;
J
Jesse Barnes 已提交
84
	size = ALIGN(size, PAGE_SIZE);
85 86 87
	obj = i915_gem_object_create_stolen(dev, size);
	if (obj == NULL)
		obj = i915_gem_alloc_object(dev, size);
88
	if (!obj) {
89
		DRM_ERROR("failed to allocate framebuffer\n");
J
Jesse Barnes 已提交
90 91 92 93
		ret = -ENOMEM;
		goto out;
	}

94
	/* Flush everything out, we'll be doing GTT only from now on */
95
	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
J
Jesse Barnes 已提交
96
	if (ret) {
97
		DRM_ERROR("failed to pin obj: %d\n", ret);
J
Jesse Barnes 已提交
98 99 100
		goto out_unref;
	}

101 102 103
	fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
	if (IS_ERR(fb)) {
		ret = PTR_ERR(fb);
104
		goto out_unpin;
105 106 107
	}

	ifbdev->fb = to_intel_framebuffer(fb);
108 109 110 111

	return 0;

out_unpin:
B
Ben Widawsky 已提交
112
	i915_gem_object_ggtt_unpin(obj);
113 114 115 116 117 118 119 120 121 122 123
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);
124
	struct intel_framebuffer *intel_fb = ifbdev->fb;
125 126 127 128 129 130
	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;
131
	bool prealloc = false;
132 133 134

	mutex_lock(&dev->struct_mutex);

135 136 137 138 139 140 141 142 143 144
	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;
	}
145
	if (!intel_fb || WARN_ON(!intel_fb->obj)) {
146
		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
147 148 149
		ret = intelfb_alloc(helper, sizes);
		if (ret)
			goto out_unlock;
150
		intel_fb = ifbdev->fb;
151
	} else {
152
		DRM_DEBUG_KMS("re-using BIOS fb\n");
153
		prealloc = true;
154 155 156 157 158 159 160 161
		sizes->fb_width = intel_fb->base.width;
		sizes->fb_height = intel_fb->base.height;
	}

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

	info = framebuffer_alloc(0, &dev->pdev->dev);
J
Jesse Barnes 已提交
162 163
	if (!info) {
		ret = -ENOMEM;
164
		goto out_unpin;
J
Jesse Barnes 已提交
165 166
	}

167
	info->par = helper;
J
Jesse Barnes 已提交
168

169
	fb = &ifbdev->fb->base;
J
Jesse Barnes 已提交
170

171 172
	ifbdev->helper.fb = fb;
	ifbdev->helper.fbdev = info;
173

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

176
	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
J
Jesse Barnes 已提交
177 178
	info->fbops = &intelfb_ops;

179 180 181 182 183
	ret = fb_alloc_cmap(&info->cmap, 256, 0);
	if (ret) {
		ret = -ENOMEM;
		goto out_unpin;
	}
184
	/* setup aperture base/size for vesafb takeover */
185 186 187 188 189 190
	info->apertures = alloc_apertures(1);
	if (!info->apertures) {
		ret = -ENOMEM;
		goto out_unpin;
	}
	info->apertures->ranges[0].base = dev->mode_config.fb_base;
191
	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
192

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

196
	info->screen_base =
197
		ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),
198
			   size);
J
Jesse Barnes 已提交
199 200
	if (!info->screen_base) {
		ret = -ENOSPC;
201
		goto out_unpin;
J
Jesse Barnes 已提交
202 203 204
	}
	info->screen_size = size;

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

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

211 212 213 214
	/* 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.
	 */
215
	if (ifbdev->fb->obj->stolen && !prealloc)
216 217
		memset_io(info->screen_base, 0, info->screen_size);

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

220
	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n",
221
		      fb->width, fb->height,
222
		      i915_gem_obj_ggtt_offset(obj), obj);
J
Jesse Barnes 已提交
223 224

	mutex_unlock(&dev->struct_mutex);
225
	vga_switcheroo_client_fb_set(dev->pdev, info);
J
Jesse Barnes 已提交
226 227
	return 0;

228
out_unpin:
B
Ben Widawsky 已提交
229
	i915_gem_object_ggtt_unpin(obj);
230
	drm_gem_object_unreference(&obj->base);
231
out_unlock:
J
Jesse Barnes 已提交
232 233 234 235
	mutex_unlock(&dev->struct_mutex);
	return ret;
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
/** 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;
}

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
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,
				    bool *enabled, int width, int height)
{
301
	struct drm_device *dev = fb_helper->dev;
302
	int i, j;
303
	bool *save_enabled;
304
	bool fallback = true;
305 306
	int num_connectors_enabled = 0;
	int num_connectors_detected = 0;
307

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
	/*
	 * If the user specified any force options, just bail here
	 * and use that config.
	 */
	for (i = 0; i < fb_helper->connector_count; i++) {
		struct drm_fb_helper_connector *fb_conn;
		struct drm_connector *connector;

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

		if (!enabled[i])
			continue;

		if (connector->force != DRM_FORCE_UNSPECIFIED)
			return false;
	}

326 327 328 329 330 331
	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);
332 333 334 335 336 337 338 339 340

	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;
341 342 343 344

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

345 346 347 348 349 350 351 352 353 354 355 356 357 358
		if (!enabled[i]) {
			DRM_DEBUG_KMS("connector %d not enabled, skipping\n",
				      connector->base.id);
			continue;
		}

		encoder = connector->encoder;
		if (!encoder || WARN_ON(!encoder->crtc)) {
			DRM_DEBUG_KMS("connector %d has no encoder or crtc, skipping\n",
				      connector->base.id);
			enabled[i] = false;
			continue;
		}

359 360
		num_connectors_enabled++;

361 362 363 364 365 366 367 368
		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++) {
369
			if (crtcs[j] == new_crtc) {
370
				DRM_DEBUG_KMS("fallback: cloned configuration\n");
371
				fallback = true;
372 373
				goto out;
			}
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
		}

		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
			      fb_conn->connector->base.id);

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

		/* try for preferred next */
		if (!modes[i]) {
			DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
				      fb_conn->connector->base.id);
			modes[i] = drm_has_preferred_mode(fb_conn, width,
							  height);
		}

		/* 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
			 * usually contains. But since our current fastboot
			 * code puts a mode derived from the post-pfit timings
			 * into crtc->mode this works out correctly. We don't
			 * use hwmode anywhere right now, so use it for this
			 * since the fb helper layer wants a pointer to
			 * something we own.
			 */
			intel_mode_from_pipe_config(&encoder->crtc->hwmode,
						    &to_intel_crtc(encoder->crtc)->config);
			modes[i] = &encoder->crtc->hwmode;
		}
		crtcs[i] = new_crtc;

		DRM_DEBUG_KMS("connector %s on crtc %d: %s\n",
			      drm_get_connector_name(connector),
			      encoder->crtc->base.id,
			      modes[i]->name);
413

414
		fallback = false;
415 416
	}

417 418 419 420 421 422 423 424 425 426 427 428 429
	/*
	 * 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;
	}

430
out:
431
	if (fallback) {
432
		DRM_DEBUG_KMS("Not using firmware configuration\n");
433 434 435
		memcpy(enabled, save_enabled, dev->mode_config.num_connector);
		kfree(save_enabled);
		return false;
436 437
	}

438
	kfree(save_enabled);
439 440 441
	return true;
}

442
static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
443
	.initial_config = intel_fb_initial_config,
444 445
	.gamma_set = intel_crtc_fb_gamma_set,
	.gamma_get = intel_crtc_fb_gamma_get,
446
	.fb_probe = intelfb_create,
447
};
J
Jesse Barnes 已提交
448

449 450
static void intel_fbdev_destroy(struct drm_device *dev,
				struct intel_fbdev *ifbdev)
J
Jesse Barnes 已提交
451
{
452
	if (ifbdev->helper.fbdev) {
453 454
		struct fb_info *info = ifbdev->helper.fbdev;

J
Jesse Barnes 已提交
455 456
		unregister_framebuffer(info);
		iounmap(info->screen_base);
457 458
		if (info->cmap.len)
			fb_dealloc_cmap(&info->cmap);
459

J
Jesse Barnes 已提交
460 461 462
		framebuffer_release(info);
	}

463
	drm_fb_helper_fini(&ifbdev->helper);
J
Jesse Barnes 已提交
464

465
	drm_framebuffer_unregister_private(&ifbdev->fb->base);
466
	drm_framebuffer_remove(&ifbdev->fb->base);
J
Jesse Barnes 已提交
467
}
468

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
/*
 * 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;
	struct intel_plane_config *plane_config = NULL;
	unsigned int max_size = 0;

	if (!i915.fastboot)
		return false;

	/* Find the largest fb */
491
	for_each_crtc(dev, crtc) {
492 493
		intel_crtc = to_intel_crtc(crtc);

494
		if (!intel_crtc->active || !crtc->primary->fb) {
495 496 497 498 499 500 501 502 503
			DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
				      pipe_name(intel_crtc->pipe));
			continue;
		}

		if (intel_crtc->plane_config.size > max_size) {
			DRM_DEBUG_KMS("found possible fb from plane %c\n",
				      pipe_name(intel_crtc->pipe));
			plane_config = &intel_crtc->plane_config;
504
			fb = to_intel_framebuffer(crtc->primary->fb);
505 506 507 508 509 510 511 512 513 514
			max_size = plane_config->size;
		}
	}

	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 */
515
	for_each_crtc(dev, crtc) {
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
		unsigned int cur_size;

		intel_crtc = to_intel_crtc(crtc);

		if (!intel_crtc->active) {
			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
531 532
		 * pipe.  Note we need to use the selected fb's pitch and bpp
		 * rather than the current pipe's, since they differ.
533
		 */
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
		cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay;
		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]);
			plane_config = NULL;
			fb = NULL;
			break;
		}

		cur_size = intel_crtc->config.adjusted_mode.crtc_vdisplay;
		cur_size = ALIGN(cur_size, plane_config->tiled ? (IS_GEN2(dev) ? 16 : 8) : 1);
		cur_size *= fb->base.pitches[0];
		DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
			      pipe_name(intel_crtc->pipe),
			      intel_crtc->config.adjusted_mode.crtc_hdisplay,
			      intel_crtc->config.adjusted_mode.crtc_vdisplay,
			      fb->base.bits_per_pixel,
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
			      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);
			plane_config = NULL;
			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;
	}

574
	ifbdev->preferred_bpp = fb->base.bits_per_pixel;
575 576
	ifbdev->fb = fb;

577
	drm_framebuffer_reference(&ifbdev->fb->base);
578 579

	/* Final pass to check if any active pipes don't have fbs */
580
	for_each_crtc(dev, crtc) {
581 582 583 584 585
		intel_crtc = to_intel_crtc(crtc);

		if (!intel_crtc->active)
			continue;

586
		WARN(!crtc->primary->fb,
587 588 589 590 591 592 593 594 595 596 597 598 599
		     "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;
}

600 601
int intel_fbdev_init(struct drm_device *dev)
{
602
	struct intel_fbdev *ifbdev;
603
	struct drm_i915_private *dev_priv = dev->dev_private;
604
	int ret;
605

606 607 608 609 610
	if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
		return -ENODEV;

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

613
	ifbdev->helper.funcs = &intel_fb_helper_funcs;
614 615
	if (!intel_fbdev_init_bios(dev, ifbdev))
		ifbdev->preferred_bpp = 32;
616

617
	ret = drm_fb_helper_init(dev, &ifbdev->helper,
618
				 INTEL_INFO(dev)->num_pipes, 4);
619 620 621 622
	if (ret) {
		kfree(ifbdev);
		return ret;
	}
623

624
	dev_priv->fbdev = ifbdev;
625
	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
626

J
Jesse Barnes 已提交
627 628
	return 0;
}
629

630 631
void intel_fbdev_initial_config(struct drm_device *dev)
{
632
	struct drm_i915_private *dev_priv = dev->dev_private;
633
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
634 635

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

639 640
void intel_fbdev_fini(struct drm_device *dev)
{
641
	struct drm_i915_private *dev_priv = dev->dev_private;
642 643 644
	if (!dev_priv->fbdev)
		return;

645
	intel_fbdev_destroy(dev, dev_priv->fbdev);
646
	kfree(dev_priv->fbdev);
647 648
	dev_priv->fbdev = NULL;
}
649 650 651

void intel_fbdev_set_suspend(struct drm_device *dev, int state)
{
652
	struct drm_i915_private *dev_priv = dev->dev_private;
653 654 655 656
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
	struct fb_info *info;

	if (!ifbdev)
657 658
		return;

659 660 661 662 663 664
	info = ifbdev->helper.fbdev;

	/* 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.
	 */
665
	if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen)
666 667 668
		memset_io(info->screen_base, 0, info->screen_size);

	fb_set_suspend(info, state);
669 670
}

671
void intel_fbdev_output_poll_changed(struct drm_device *dev)
672
{
673
	struct drm_i915_private *dev_priv = dev->dev_private;
674 675
	if (dev_priv->fbdev)
		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
676
}
677

678
void intel_fbdev_restore_mode(struct drm_device *dev)
679 680
{
	int ret;
681
	struct drm_i915_private *dev_priv = dev->dev_private;
682

683
	if (!dev_priv->fbdev)
B
Ben Widawsky 已提交
684 685
		return;

686
	drm_modeset_lock_all(dev);
687

688 689 690
	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
	if (ret)
		DRM_DEBUG("failed to restore crtc mode\n");
691

692
	drm_modeset_unlock_all(dev);
693
}