intel_fbdev.c 22.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
/*
 * 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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
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) {
		/*
		 * FIXME: fbdev presumes that all callbacks also work from
		 * atomic contexts and relies on that for emergency oops
		 * printing. KMS totally doesn't do that and the locking here is
		 * by far not the only place this goes wrong.  Ignore this for
		 * now until we solve this for real.
		 */
		mutex_lock(&fb_helper->dev->struct_mutex);
		ret = i915_gem_object_set_to_gtt_domain(ifbdev->fb->obj,
							true);
		mutex_unlock(&fb_helper->dev->struct_mutex);
	}

	return ret;
}

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
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) {
		/*
		 * FIXME: fbdev presumes that all callbacks also work from
		 * atomic contexts and relies on that for emergency oops
		 * printing. KMS totally doesn't do that and the locking here is
		 * by far not the only place this goes wrong.  Ignore this for
		 * now until we solve this for real.
		 */
		mutex_lock(&fb_helper->dev->struct_mutex);
		intel_fb_obj_invalidate(ifbdev->fb->obj, NULL, ORIGIN_GTT);
		mutex_unlock(&fb_helper->dev->struct_mutex);
	}

	return ret;
}

J
Jesse Barnes 已提交
99 100
static struct fb_ops intelfb_ops = {
	.owner = THIS_MODULE,
101
	.fb_check_var = drm_fb_helper_check_var,
102
	.fb_set_par = intel_fbdev_set_par,
J
Jesse Barnes 已提交
103 104 105
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
106
	.fb_pan_display = drm_fb_helper_pan_display,
107
	.fb_blank = intel_fbdev_blank,
108
	.fb_setcmap = drm_fb_helper_setcmap,
J
Jesse Barnes 已提交
109 110
	.fb_debug_enter = drm_fb_helper_debug_enter,
	.fb_debug_leave = drm_fb_helper_debug_leave,
J
Jesse Barnes 已提交
111 112
};

113 114
static int intelfb_alloc(struct drm_fb_helper *helper,
			 struct drm_fb_helper_surface_size *sizes)
J
Jesse Barnes 已提交
115
{
116 117
	struct intel_fbdev *ifbdev =
		container_of(helper, struct intel_fbdev, helper);
118
	struct drm_framebuffer *fb;
119
	struct drm_device *dev = helper->dev;
120
	struct drm_mode_fb_cmd2 mode_cmd = {};
121
	struct drm_i915_gem_object *obj;
122
	int size, ret;
J
Jesse Barnes 已提交
123

124
	/* we don't do packed 24bpp */
125 126
	if (sizes->surface_bpp == 24)
		sizes->surface_bpp = 32;
127

128 129
	mode_cmd.width = sizes->surface_width;
	mode_cmd.height = sizes->surface_height;
J
Jesse Barnes 已提交
130

131 132
	mode_cmd.pitches[0] = ALIGN(mode_cmd.width *
				    DIV_ROUND_UP(sizes->surface_bpp, 8), 64);
133 134
	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
							  sizes->surface_depth);
J
Jesse Barnes 已提交
135

136
	size = mode_cmd.pitches[0] * mode_cmd.height;
137
	size = PAGE_ALIGN(size);
138 139 140
	obj = i915_gem_object_create_stolen(dev, size);
	if (obj == NULL)
		obj = i915_gem_alloc_object(dev, size);
141
	if (!obj) {
142
		DRM_ERROR("failed to allocate framebuffer\n");
J
Jesse Barnes 已提交
143 144 145 146
		ret = -ENOMEM;
		goto out;
	}

147 148 149
	fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
	if (IS_ERR(fb)) {
		ret = PTR_ERR(fb);
150 151 152 153
		goto out_unref;
	}

	/* Flush everything out, we'll be doing GTT only from now on */
154
	ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL);
155 156 157
	if (ret) {
		DRM_ERROR("failed to pin obj: %d\n", ret);
		goto out_fb;
158 159 160
	}

	ifbdev->fb = to_intel_framebuffer(fb);
161 162 163

	return 0;

164 165
out_fb:
	drm_framebuffer_remove(fb);
166 167 168 169 170 171 172 173 174 175 176
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);
177
	struct intel_framebuffer *intel_fb = ifbdev->fb;
178 179 180 181 182 183
	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;
184
	bool prealloc = false;
185 186 187

	mutex_lock(&dev->struct_mutex);

188 189 190 191 192 193 194 195 196 197
	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;
	}
198
	if (!intel_fb || WARN_ON(!intel_fb->obj)) {
199
		DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
200 201 202
		ret = intelfb_alloc(helper, sizes);
		if (ret)
			goto out_unlock;
203
		intel_fb = ifbdev->fb;
204
	} else {
205
		DRM_DEBUG_KMS("re-using BIOS fb\n");
206
		prealloc = true;
207 208 209 210 211 212 213 214
		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 已提交
215 216
	if (!info) {
		ret = -ENOMEM;
217
		goto out_unpin;
J
Jesse Barnes 已提交
218 219
	}

220
	info->par = helper;
J
Jesse Barnes 已提交
221

222
	fb = &ifbdev->fb->base;
J
Jesse Barnes 已提交
223

224 225
	ifbdev->helper.fb = fb;
	ifbdev->helper.fbdev = info;
226

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

229
	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
J
Jesse Barnes 已提交
230 231
	info->fbops = &intelfb_ops;

232 233 234 235 236
	ret = fb_alloc_cmap(&info->cmap, 256, 0);
	if (ret) {
		ret = -ENOMEM;
		goto out_unpin;
	}
237
	/* setup aperture base/size for vesafb takeover */
238 239 240 241 242 243
	info->apertures = alloc_apertures(1);
	if (!info->apertures) {
		ret = -ENOMEM;
		goto out_unpin;
	}
	info->apertures->ranges[0].base = dev->mode_config.fb_base;
244
	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
245

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

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

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

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

264 265 266 267
	/* 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.
	 */
268
	if (ifbdev->fb->obj->stolen && !prealloc)
269 270
		memset_io(info->screen_base, 0, info->screen_size);

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

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

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

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

289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
/** 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;
}

310 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
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,
352
				    struct drm_fb_offset *offsets,
353 354
				    bool *enabled, int width, int height)
{
355
	struct drm_device *dev = fb_helper->dev;
356
	int i, j;
357
	bool *save_enabled;
358
	bool fallback = true;
359 360
	int num_connectors_enabled = 0;
	int num_connectors_detected = 0;
361 362
	uint64_t conn_configured = 0, mask;
	int pass = 0;
363 364 365 366 367 368 369

	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);
370 371
	mask = (1 << fb_helper->connector_count) - 1;
retry:
372 373 374 375 376 377 378 379
	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;
380

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

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

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

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

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

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

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

416 417
		num_connectors_enabled++;

418 419 420 421 422 423 424 425
		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++) {
426
			if (crtcs[j] == new_crtc) {
427
				DRM_DEBUG_KMS("fallback: cloned configuration\n");
428
				goto bail;
429
			}
430 431
		}

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

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

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

446 447 448
		/* 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",
449
				      connector->name);
450 451 452 453 454
			modes[i] = list_first_entry(&connector->modes,
						    struct drm_display_mode,
						    head);
		}

455 456 457 458 459 460 461 462 463 464 465 466 467
		/* 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.
			 */
468
			DRM_DEBUG_KMS("looking for current mode on connector %s\n",
469
				      connector->name);
470
			intel_mode_from_pipe_config(&encoder->crtc->hwmode,
471
						    to_intel_crtc(encoder->crtc)->config);
472 473 474 475
			modes[i] = &encoder->crtc->hwmode;
		}
		crtcs[i] = new_crtc;

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

483
		fallback = false;
484 485 486 487 488 489
		conn_configured |= (1 << i);
	}

	if ((conn_configured & mask) != mask) {
		pass++;
		goto retry;
490 491
	}

492 493 494 495 496 497 498 499 500 501 502 503 504
	/*
	 * 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;
	}

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

513
	kfree(save_enabled);
514 515 516
	return true;
}

517
static const struct drm_fb_helper_funcs intel_fb_helper_funcs = {
518
	.initial_config = intel_fb_initial_config,
519 520
	.gamma_set = intel_crtc_fb_gamma_set,
	.gamma_get = intel_crtc_fb_gamma_get,
521
	.fb_probe = intelfb_create,
522
};
J
Jesse Barnes 已提交
523

524 525
static void intel_fbdev_destroy(struct drm_device *dev,
				struct intel_fbdev *ifbdev)
J
Jesse Barnes 已提交
526
{
527
	if (ifbdev->helper.fbdev) {
528 529
		struct fb_info *info = ifbdev->helper.fbdev;

J
Jesse Barnes 已提交
530 531
		unregister_framebuffer(info);
		iounmap(info->screen_base);
532 533
		if (info->cmap.len)
			fb_dealloc_cmap(&info->cmap);
534

J
Jesse Barnes 已提交
535 536 537
		framebuffer_release(info);
	}

538
	drm_fb_helper_fini(&ifbdev->helper);
J
Jesse Barnes 已提交
539

540
	drm_framebuffer_unregister_private(&ifbdev->fb->base);
541
	drm_framebuffer_remove(&ifbdev->fb->base);
J
Jesse Barnes 已提交
542
}
543

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
/*
 * 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;
559
	struct intel_initial_plane_config *plane_config = NULL;
560 561 562 563 564 565
	unsigned int max_size = 0;

	if (!i915.fastboot)
		return false;

	/* Find the largest fb */
566
	for_each_crtc(dev, crtc) {
567 568
		intel_crtc = to_intel_crtc(crtc);

569
		if (!intel_crtc->active || !crtc->primary->fb) {
570 571 572 573 574 575 576 577 578
			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;
579
			fb = to_intel_framebuffer(crtc->primary->fb);
580 581 582 583 584 585 586 587 588 589
			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 */
590
	for_each_crtc(dev, crtc) {
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
		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
606 607
		 * pipe.  Note we need to use the selected fb's pitch and bpp
		 * rather than the current pipe's, since they differ.
608
		 */
609
		cur_size = intel_crtc->config->base.adjusted_mode.crtc_hdisplay;
610 611 612 613 614 615 616 617 618 619
		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;
		}

620
		cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
621
		cur_size = intel_fb_align_height(dev, cur_size,
622 623
						 fb->base.pixel_format,
						 fb->base.modifier[0]);
624 625 626
		cur_size *= fb->base.pitches[0];
		DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
			      pipe_name(intel_crtc->pipe),
627 628
			      intel_crtc->config->base.adjusted_mode.crtc_hdisplay,
			      intel_crtc->config->base.adjusted_mode.crtc_vdisplay,
629
			      fb->base.bits_per_pixel,
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
			      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;
	}

651
	ifbdev->preferred_bpp = fb->base.bits_per_pixel;
652 653
	ifbdev->fb = fb;

654
	drm_framebuffer_reference(&ifbdev->fb->base);
655 656

	/* Final pass to check if any active pipes don't have fbs */
657
	for_each_crtc(dev, crtc) {
658 659 660 661 662
		intel_crtc = to_intel_crtc(crtc);

		if (!intel_crtc->active)
			continue;

663
		WARN(!crtc->primary->fb,
664 665 666 667 668 669 670 671 672 673 674 675 676
		     "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;
}

677 678 679 680 681 682 683 684 685
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);
}

686 687
int intel_fbdev_init(struct drm_device *dev)
{
688
	struct intel_fbdev *ifbdev;
689
	struct drm_i915_private *dev_priv = dev->dev_private;
690
	int ret;
691

692 693 694 695 696
	if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
		return -ENODEV;

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

699 700
	drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs);

701 702
	if (!intel_fbdev_init_bios(dev, ifbdev))
		ifbdev->preferred_bpp = 32;
703

704
	ret = drm_fb_helper_init(dev, &ifbdev->helper,
705
				 INTEL_INFO(dev)->num_pipes, 4);
706 707 708 709
	if (ret) {
		kfree(ifbdev);
		return ret;
	}
710

711
	dev_priv->fbdev = ifbdev;
712 713
	INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);

714
	drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
715

J
Jesse Barnes 已提交
716 717
	return 0;
}
718

719
void intel_fbdev_initial_config(void *data, async_cookie_t cookie)
720
{
721
	struct drm_i915_private *dev_priv = data;
722
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
723 724

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

728 729
void intel_fbdev_fini(struct drm_device *dev)
{
730
	struct drm_i915_private *dev_priv = dev->dev_private;
731 732 733
	if (!dev_priv->fbdev)
		return;

734 735
	flush_work(&dev_priv->fbdev_suspend_work);

736
	async_synchronize_full();
737
	intel_fbdev_destroy(dev, dev_priv->fbdev);
738
	kfree(dev_priv->fbdev);
739 740
	dev_priv->fbdev = NULL;
}
741

742
void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
743
{
744
	struct drm_i915_private *dev_priv = dev->dev_private;
745 746 747 748
	struct intel_fbdev *ifbdev = dev_priv->fbdev;
	struct fb_info *info;

	if (!ifbdev)
749 750
		return;

751 752
	info = ifbdev->helper.fbdev;

753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
	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;
		}
	}

780 781 782 783
	/* 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.
	 */
784
	if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen)
785 786 787
		memset_io(info->screen_base, 0, info->screen_size);

	fb_set_suspend(info, state);
788
	console_unlock();
789 790
}

791
void intel_fbdev_output_poll_changed(struct drm_device *dev)
792
{
793
	struct drm_i915_private *dev_priv = dev->dev_private;
794 795
	if (dev_priv->fbdev)
		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
796
}
797

798
void intel_fbdev_restore_mode(struct drm_device *dev)
799 800
{
	int ret;
801
	struct drm_i915_private *dev_priv = dev->dev_private;
802

803
	if (!dev_priv->fbdev)
B
Ben Widawsky 已提交
804 805
		return;

806
	ret = drm_fb_helper_restore_fbdev_mode_unlocked(&dev_priv->fbdev->helper);
807 808 809
	if (ret)
		DRM_DEBUG("failed to restore crtc mode\n");
}