intel_fbdev.c 19.8 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
		if (!enabled[i]) {
346
			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
347
				      connector->name);
348 349 350 351 352
			continue;
		}

		encoder = connector->encoder;
		if (!encoder || WARN_ON(!encoder->crtc)) {
353
			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
354
				      connector->name);
355 356 357 358
			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
		DRM_DEBUG_KMS("looking for cmdline mode on connector %s\n",
377
			      connector->name);
378 379 380 381 382 383

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

		/* try for preferred next */
		if (!modes[i]) {
384
			DRM_DEBUG_KMS("looking for preferred mode on connector %s\n",
385
				      connector->name);
386 387 388 389
			modes[i] = drm_has_preferred_mode(fb_conn, width,
							  height);
		}

390 391 392
		/* 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",
393
				      connector->name);
394 395 396 397 398
			modes[i] = list_first_entry(&connector->modes,
						    struct drm_display_mode,
						    head);
		}

399 400 401 402 403 404 405 406 407 408 409 410 411
		/* 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.
			 */
412
			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
413
				      connector->name);
414 415 416 417 418 419
			intel_mode_from_pipe_config(&encoder->crtc->hwmode,
						    &to_intel_crtc(encoder->crtc)->config);
			modes[i] = &encoder->crtc->hwmode;
		}
		crtcs[i] = new_crtc;

420
		DRM_DEBUG_KMS("connector %s on pipe %d [CRTC:%d]: %dx%d%s\n",
421
			      connector->name,
422
			      pipe_name(to_intel_crtc(encoder->crtc)->pipe),
423
			      encoder->crtc->base.id,
424 425
			      modes[i]->hdisplay, modes[i]->vdisplay,
			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
426

427
		fallback = false;
428 429
	}

430 431 432 433 434 435 436 437 438 439 440 441 442
	/*
	 * 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;
	}

443
out:
444
	if (fallback) {
445
		DRM_DEBUG_KMS("Not using firmware configuration\n");
446 447 448
		memcpy(enabled, save_enabled, dev->mode_config.num_connector);
		kfree(save_enabled);
		return false;
449 450
	}

451
	kfree(save_enabled);
452 453 454
	return true;
}

455
static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
456
	.initial_config = intel_fb_initial_config,
457 458
	.gamma_set = intel_crtc_fb_gamma_set,
	.gamma_get = intel_crtc_fb_gamma_get,
459
	.fb_probe = intelfb_create,
460
};
J
Jesse Barnes 已提交
461

462 463
static void intel_fbdev_destroy(struct drm_device *dev,
				struct intel_fbdev *ifbdev)
J
Jesse Barnes 已提交
464
{
465
	if (ifbdev->helper.fbdev) {
466 467
		struct fb_info *info = ifbdev->helper.fbdev;

J
Jesse Barnes 已提交
468 469
		unregister_framebuffer(info);
		iounmap(info->screen_base);
470 471
		if (info->cmap.len)
			fb_dealloc_cmap(&info->cmap);
472

J
Jesse Barnes 已提交
473 474 475
		framebuffer_release(info);
	}

476
	drm_fb_helper_fini(&ifbdev->helper);
J
Jesse Barnes 已提交
477

478
	drm_framebuffer_unregister_private(&ifbdev->fb->base);
479
	drm_framebuffer_remove(&ifbdev->fb->base);
J
Jesse Barnes 已提交
480
}
481

482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
/*
 * 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 */
504
	for_each_crtc(dev, crtc) {
505 506
		intel_crtc = to_intel_crtc(crtc);

507
		if (!intel_crtc->active || !crtc->primary->fb) {
508 509 510 511 512 513 514 515 516
			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;
517
			fb = to_intel_framebuffer(crtc->primary->fb);
518 519 520 521 522 523 524 525 526 527
			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 */
528
	for_each_crtc(dev, crtc) {
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
		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
544 545
		 * pipe.  Note we need to use the selected fb's pitch and bpp
		 * rather than the current pipe's, since they differ.
546
		 */
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
		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,
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
			      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;
	}

587
	ifbdev->preferred_bpp = fb->base.bits_per_pixel;
588 589
	ifbdev->fb = fb;

590
	drm_framebuffer_reference(&ifbdev->fb->base);
591 592

	/* Final pass to check if any active pipes don't have fbs */
593
	for_each_crtc(dev, crtc) {
594 595 596 597 598
		intel_crtc = to_intel_crtc(crtc);

		if (!intel_crtc->active)
			continue;

599
		WARN(!crtc->primary->fb,
600 601 602 603 604 605 606 607 608 609 610 611 612
		     "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;
}

613 614
int intel_fbdev_init(struct drm_device *dev)
{
615
	struct intel_fbdev *ifbdev;
616
	struct drm_i915_private *dev_priv = dev->dev_private;
617
	int ret;
618

619 620 621 622 623
	if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
		return -ENODEV;

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

626
	ifbdev->helper.funcs = &intel_fb_helper_funcs;
627 628
	if (!intel_fbdev_init_bios(dev, ifbdev))
		ifbdev->preferred_bpp = 32;
629

630
	ret = drm_fb_helper_init(dev, &ifbdev->helper,
631
				 INTEL_INFO(dev)->num_pipes, 4);
632 633 634 635
	if (ret) {
		kfree(ifbdev);
		return ret;
	}
636

637
	dev_priv->fbdev = ifbdev;
638
	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
639

J
Jesse Barnes 已提交
640 641
	return 0;
}
642

643 644
void intel_fbdev_initial_config(struct drm_device *dev)
{
645
	struct drm_i915_private *dev_priv = dev->dev_private;
646
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
647 648

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

652 653
void intel_fbdev_fini(struct drm_device *dev)
{
654
	struct drm_i915_private *dev_priv = dev->dev_private;
655 656 657
	if (!dev_priv->fbdev)
		return;

658
	intel_fbdev_destroy(dev, dev_priv->fbdev);
659
	kfree(dev_priv->fbdev);
660 661
	dev_priv->fbdev = NULL;
}
662 663 664

void intel_fbdev_set_suspend(struct drm_device *dev, int state)
{
665
	struct drm_i915_private *dev_priv = dev->dev_private;
666 667 668 669
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
	struct fb_info *info;

	if (!ifbdev)
670 671
		return;

672 673 674 675 676 677
	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.
	 */
678
	if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen)
679 680 681
		memset_io(info->screen_base, 0, info->screen_size);

	fb_set_suspend(info, state);
682 683
}

684
void intel_fbdev_output_poll_changed(struct drm_device *dev)
685
{
686
	struct drm_i915_private *dev_priv = dev->dev_private;
687 688
	if (dev_priv->fbdev)
		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
689
}
690

691
void intel_fbdev_restore_mode(struct drm_device *dev)
692 693
{
	int ret;
694
	struct drm_i915_private *dev_priv = dev->dev_private;
695

696
	if (!dev_priv->fbdev)
B
Ben Widawsky 已提交
697 698
		return;

699
	ret = drm_fb_helper_restore_fbdev_mode_unlocked(&dev_priv->fbdev->helper);
700 701 702
	if (ret)
		DRM_DEBUG("failed to restore crtc mode\n");
}