nouveau_display.c 18.2 KB
Newer Older
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 (C) 2008 Maarten Maathuis.
 * All Rights Reserved.
 *
 * 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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS 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.
 *
 */

27 28
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
29
#include <drm/ttm/ttm_execbuf_util.h>
30

31
#include "nouveau_fbcon.h"
32
#include "dispnv04/hw.h"
33 34
#include "nouveau_crtc.h"
#include "nouveau_dma.h"
35
#include "nouveau_gem.h"
36
#include "nouveau_connector.h"
37
#include "nv50_display.h"
38

39 40
#include "nouveau_fence.h"

41
#include <subdev/bios/gpio.h>
42 43
#include <subdev/gpio.h>
#include <engine/disp.h>
44

45 46
#include <core/class.h>

47 48 49 50 51
static void
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
{
	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);

52 53
	if (fb->nvbo)
		drm_gem_object_unreference_unlocked(fb->nvbo->gem);
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

	drm_framebuffer_cleanup(drm_fb);
	kfree(fb);
}

static int
nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
				       struct drm_file *file_priv,
				       unsigned int *handle)
{
	struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);

	return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle);
}

static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
	.destroy = nouveau_user_framebuffer_destroy,
	.create_handle = nouveau_user_framebuffer_create_handle,
};

74
int
75 76
nouveau_framebuffer_init(struct drm_device *dev,
			 struct nouveau_framebuffer *nv_fb,
77
			 struct drm_mode_fb_cmd2 *mode_cmd,
78
			 struct nouveau_bo *nvbo)
79
{
80
	struct nouveau_drm *drm = nouveau_drm(dev);
81
	struct drm_framebuffer *fb = &nv_fb->base;
82 83
	int ret;

84 85 86
	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
	nv_fb->nvbo = nvbo;

87
	if (nv_device(drm->device)->card_type >= NV_50) {
88 89 90 91 92 93 94 95 96 97 98
		u32 tile_flags = nouveau_bo_tile_layout(nvbo);
		if (tile_flags == 0x7a00 ||
		    tile_flags == 0xfe00)
			nv_fb->r_dma = NvEvoFB32;
		else
		if (tile_flags == 0x7000)
			nv_fb->r_dma = NvEvoFB16;
		else
			nv_fb->r_dma = NvEvoVRAM_LP;

		switch (fb->depth) {
99 100 101
		case  8: nv_fb->r_format = 0x1e00; break;
		case 15: nv_fb->r_format = 0xe900; break;
		case 16: nv_fb->r_format = 0xe800; break;
102
		case 24:
103 104
		case 32: nv_fb->r_format = 0xcf00; break;
		case 30: nv_fb->r_format = 0xd100; break;
105
		default:
106
			 NV_ERROR(drm, "unknown depth %d\n", fb->depth);
107 108 109
			 return -EINVAL;
		}

110
		if (nv_device(drm->device)->chipset == 0x50)
111 112
			nv_fb->r_format |= (tile_flags << 8);

113
		if (!tile_flags) {
114
			if (nv_device(drm->device)->card_type < NV_D0)
115
				nv_fb->r_pitch = 0x00100000 | fb->pitches[0];
116
			else
117
				nv_fb->r_pitch = 0x01000000 | fb->pitches[0];
118
		} else {
119
			u32 mode = nvbo->tile_mode;
120
			if (nv_device(drm->device)->card_type >= NV_C0)
121
				mode >>= 4;
122
			nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode;
123 124 125
		}
	}

126 127 128 129 130
	ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
	if (ret) {
		return ret;
	}

131
	return 0;
132 133 134 135 136
}

static struct drm_framebuffer *
nouveau_user_framebuffer_create(struct drm_device *dev,
				struct drm_file *file_priv,
137
				struct drm_mode_fb_cmd2 *mode_cmd)
138
{
139
	struct nouveau_framebuffer *nouveau_fb;
140
	struct drm_gem_object *gem;
141
	int ret = -ENOMEM;
142

143
	gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
144
	if (!gem)
145
		return ERR_PTR(-ENOENT);
146

147 148
	nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
	if (!nouveau_fb)
149
		goto err_unref;
150 151

	ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
152 153
	if (ret)
		goto err;
154

155
	return &nouveau_fb->base;
156 157 158 159 160 161

err:
	kfree(nouveau_fb);
err_unref:
	drm_gem_object_unreference(gem);
	return ERR_PTR(ret);
162 163
}

164
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
165
	.fb_create = nouveau_user_framebuffer_create,
166
	.output_poll_changed = nouveau_fbcon_output_poll_changed,
167 168
};

169

170
struct nouveau_drm_prop_enum_list {
171
	u8 gen_mask;
172 173 174 175
	int type;
	char *name;
};

176
static struct nouveau_drm_prop_enum_list underscan[] = {
177 178 179
	{ 6, UNDERSCAN_AUTO, "auto" },
	{ 6, UNDERSCAN_OFF, "off" },
	{ 6, UNDERSCAN_ON, "on" },
180
	{}
181 182
};

183
static struct nouveau_drm_prop_enum_list dither_mode[] = {
184 185 186 187 188 189 190 191 192
	{ 7, DITHERING_MODE_AUTO, "auto" },
	{ 7, DITHERING_MODE_OFF, "off" },
	{ 1, DITHERING_MODE_ON, "on" },
	{ 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
	{ 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
	{ 4, DITHERING_MODE_TEMPORAL, "temporal" },
	{}
};

193
static struct nouveau_drm_prop_enum_list dither_depth[] = {
194 195 196 197 198 199 200
	{ 6, DITHERING_DEPTH_AUTO, "auto" },
	{ 6, DITHERING_DEPTH_6BPC, "6 bpc" },
	{ 6, DITHERING_DEPTH_8BPC, "8 bpc" },
	{}
};

#define PROP_ENUM(p,gen,n,list) do {                                           \
201
	struct nouveau_drm_prop_enum_list *l = (list);                         \
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
	int c = 0;                                                             \
	while (l->gen_mask) {                                                  \
		if (l->gen_mask & (1 << (gen)))                                \
			c++;                                                   \
		l++;                                                           \
	}                                                                      \
	if (c) {                                                               \
		p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c);        \
		l = (list);                                                    \
		c = 0;                                                         \
		while (p && l->gen_mask) {                                     \
			if (l->gen_mask & (1 << (gen))) {                      \
				drm_property_add_enum(p, c, l->type, l->name); \
				c++;                                           \
			}                                                      \
			l++;                                                   \
		}                                                              \
	}                                                                      \
} while(0)

222 223 224
int
nouveau_display_init(struct drm_device *dev)
{
225 226 227
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct nouveau_display *disp = nouveau_display(dev);
	struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
228
	struct drm_connector *connector;
229 230 231
	int ret;

	ret = disp->init(dev);
232 233 234
	if (ret)
		return ret;

235
	/* enable polling for external displays */
236 237 238 239 240
	drm_kms_helper_poll_enable(dev);

	/* enable hotplug interrupts */
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct nouveau_connector *conn = nouveau_connector(connector);
241 242 243 244
		if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
			nouveau_event_get(gpio->events, conn->hpd.line,
					 &conn->hpd_func);
		}
245 246 247 248 249 250 251 252
	}

	return ret;
}

void
nouveau_display_fini(struct drm_device *dev)
{
253 254 255
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct nouveau_display *disp = nouveau_display(dev);
	struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
256 257 258 259 260
	struct drm_connector *connector;

	/* disable hotplug interrupts */
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct nouveau_connector *conn = nouveau_connector(connector);
261 262 263 264
		if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
			nouveau_event_put(gpio->events, conn->hpd.line,
					 &conn->hpd_func);
		}
265
	}
266 267 268 269 270

	drm_kms_helper_poll_disable(dev);
	disp->fini(dev);
}

271 272 273
int
nouveau_display_create(struct drm_device *dev)
{
274 275
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct nouveau_display *disp;
276
	u32 pclass = dev->pdev->class >> 8;
277
	int ret, gen;
278

279 280 281 282
	disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
	if (!disp)
		return -ENOMEM;

283 284
	drm_mode_config_init(dev);
	drm_mode_create_scaling_mode_property(dev);
285
	drm_mode_create_dvi_i_properties(dev);
286

287
	if (nv_device(drm->device)->card_type < NV_50)
288 289
		gen = 0;
	else
290
	if (nv_device(drm->device)->card_type < NV_D0)
291 292 293 294 295 296 297
		gen = 1;
	else
		gen = 2;

	PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
	PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
	PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
298 299

	disp->underscan_hborder_property =
300
		drm_property_create_range(dev, 0, "underscan hborder", 0, 128);
301 302

	disp->underscan_vborder_property =
303
		drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
304

305
	if (gen >= 1) {
306
		/* -90..+90 */
307
		disp->vibrant_hue_property =
308
			drm_property_create_range(dev, 0, "vibrant hue", 0, 180);
309

310
		/* -100..+100 */
311
		disp->color_vibrance_property =
312
			drm_property_create_range(dev, 0, "color vibrance", 0, 200);
313 314
	}

315
	dev->mode_config.funcs = &nouveau_mode_config_funcs;
316 317 318 319
	dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);

	dev->mode_config.min_width = 0;
	dev->mode_config.min_height = 0;
320
	if (nv_device(drm->device)->card_type < NV_10) {
321 322 323
		dev->mode_config.max_width = 2048;
		dev->mode_config.max_height = 2048;
	} else
324
	if (nv_device(drm->device)->card_type < NV_50) {
325 326 327 328 329 330 331
		dev->mode_config.max_width = 4096;
		dev->mode_config.max_height = 4096;
	} else {
		dev->mode_config.max_width = 8192;
		dev->mode_config.max_height = 8192;
	}

332 333 334
	dev->mode_config.preferred_depth = 24;
	dev->mode_config.prefer_shadow = 1;

335 336 337
	drm_kms_helper_poll_init(dev);
	drm_kms_helper_poll_disable(dev);

338 339
	if (nouveau_modeset == 1 ||
	    (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) {
340 341 342 343 344 345 346 347 348
		if (drm->vbios.dcb.entries) {
			if (nv_device(drm->device)->card_type < NV_50)
				ret = nv04_display_create(dev);
			else
				ret = nv50_display_create(dev);
		} else {
			ret = 0;
		}

349
		if (ret)
350 351 352 353 354 355 356 357 358
			goto disp_create_err;

		if (dev->mode_config.num_crtc) {
			ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
			if (ret)
				goto vblank_err;
		}

		nouveau_backlight_init(dev);
359 360
	}

361 362 363
	return 0;

vblank_err:
364
	disp->dtor(dev);
365 366 367
disp_create_err:
	drm_kms_helper_poll_fini(dev);
	drm_mode_config_cleanup(dev);
368
	return ret;
369 370 371 372 373
}

void
nouveau_display_destroy(struct drm_device *dev)
{
374
	struct nouveau_display *disp = nouveau_display(dev);
375

376
	nouveau_backlight_exit(dev);
377 378
	drm_vblank_cleanup(dev);

379 380 381
	drm_kms_helper_poll_fini(dev);
	drm_mode_config_cleanup(dev);

382 383
	if (disp->dtor)
		disp->dtor(dev);
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 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
	nouveau_drm(dev)->display = NULL;
	kfree(disp);
}

int
nouveau_display_suspend(struct drm_device *dev)
{
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct drm_crtc *crtc;

	nouveau_display_fini(dev);

	NV_INFO(drm, "unpinning framebuffer(s)...\n");
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct nouveau_framebuffer *nouveau_fb;

		nouveau_fb = nouveau_framebuffer(crtc->fb);
		if (!nouveau_fb || !nouveau_fb->nvbo)
			continue;

		nouveau_bo_unpin(nouveau_fb->nvbo);
	}

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);

		nouveau_bo_unmap(nv_crtc->cursor.nvbo);
		nouveau_bo_unpin(nv_crtc->cursor.nvbo);
	}

	return 0;
}

void
nouveau_display_resume(struct drm_device *dev)
{
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct drm_crtc *crtc;
	int ret;

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct nouveau_framebuffer *nouveau_fb;

		nouveau_fb = nouveau_framebuffer(crtc->fb);
		if (!nouveau_fb || !nouveau_fb->nvbo)
			continue;

		nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
	}

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);

		ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
		if (!ret)
			ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
		if (ret)
			NV_ERROR(drm, "Could not pin/map cursor.\n");
	}

	nouveau_fbcon_set_suspend(dev, 0);
	nouveau_fbcon_zfill_all(dev);

	nouveau_display_init(dev);

	/* Force CLUT to get re-loaded during modeset */
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);

		nv_crtc->lut.depth = 0;
	}

	drm_helper_resume_force_mode(dev);

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
		u32 offset = nv_crtc->cursor.nvbo->bo.offset;

		nv_crtc->cursor.set_offset(nv_crtc, offset);
		nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
						 nv_crtc->cursor_saved_y);
	}
467 468
}

469 470 471 472 473 474 475
static int
nouveau_page_flip_emit(struct nouveau_channel *chan,
		       struct nouveau_bo *old_bo,
		       struct nouveau_bo *new_bo,
		       struct nouveau_page_flip_state *s,
		       struct nouveau_fence **pfence)
{
476
	struct nouveau_fence_chan *fctx = chan->fence;
477 478
	struct nouveau_drm *drm = chan->drm;
	struct drm_device *dev = drm->dev;
479 480 481 482 483
	unsigned long flags;
	int ret;

	/* Queue it to the pending list */
	spin_lock_irqsave(&dev->event_lock, flags);
484
	list_add_tail(&s->head, &fctx->flip);
485 486 487 488 489 490 491 492
	spin_unlock_irqrestore(&dev->event_lock, flags);

	/* Synchronize with the old framebuffer */
	ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
	if (ret)
		goto fail;

	/* Emit the pageflip */
493
	ret = RING_SPACE(chan, 3);
494 495 496
	if (ret)
		goto fail;

497
	if (nv_device(drm->device)->card_type < NV_C0) {
498
		BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
499 500 501
		OUT_RING  (chan, 0x00000000);
		OUT_RING  (chan, 0x00000000);
	} else {
502
		BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
503
		OUT_RING  (chan, 0);
504
		BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
505
	}
506
	FIRE_RING (chan);
507

508
	ret = nouveau_fence_new(chan, false, pfence);
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
	if (ret)
		goto fail;

	return 0;
fail:
	spin_lock_irqsave(&dev->event_lock, flags);
	list_del(&s->head);
	spin_unlock_irqrestore(&dev->event_lock, flags);
	return ret;
}

int
nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
		       struct drm_pending_vblank_event *event)
{
	struct drm_device *dev = crtc->dev;
525
	struct nouveau_drm *drm = nouveau_drm(dev);
526 527 528
	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
	struct nouveau_page_flip_state *s;
529
	struct nouveau_channel *chan = NULL;
530
	struct nouveau_fence *fence;
531 532 533 534
	struct ttm_validate_buffer resv[2] = {
		{ .bo = &old_bo->bo },
		{ .bo = &new_bo->bo },
	};
535
	struct ww_acquire_ctx ticket;
536
	LIST_HEAD(res);
537 538
	int ret;

539
	if (!drm->channel)
540 541 542 543 544 545 546
		return -ENODEV;

	s = kzalloc(sizeof(*s), GFP_KERNEL);
	if (!s)
		return -ENOMEM;

	/* Choose the channel the flip will be handled in */
547
	spin_lock(&old_bo->bo.bdev->fence_lock);
548 549
	fence = new_bo->bo.sync_obj;
	if (fence)
550
		chan = fence->channel;
551
	if (!chan)
552
		chan = drm->channel;
553 554 555 556
	spin_unlock(&old_bo->bo.bdev->fence_lock);

	if (new_bo != old_bo) {
		ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
557 558
		if (ret)
			goto fail_free;
559

560
		list_add(&resv[1].head, &res);
561
	}
562 563 564 565 566 567
	list_add(&resv[0].head, &res);

	mutex_lock(&chan->cli->mutex);
	ret = ttm_eu_reserve_buffers(&ticket, &res);
	if (ret)
		goto fail_unpin;
568 569 570 571 572 573 574

	/* Initialize a page flip struct */
	*s = (struct nouveau_page_flip_state)
		{ { }, event, nouveau_crtc(crtc)->index,
		  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
		  new_bo->bo.offset };

575
	/* Emit a page flip */
576
	if (nv_device(drm->device)->card_type >= NV_50) {
577
		ret = nv50_display_flip_next(crtc, fb, chan, 0);
578
		if (ret)
B
Ben Skeggs 已提交
579 580 581
			goto fail_unreserve;
	}

582
	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
583
	mutex_unlock(&chan->cli->mutex);
584 585 586 587 588 589
	if (ret)
		goto fail_unreserve;

	/* Update the crtc struct and cleanup */
	crtc->fb = fb;

590 591
	ttm_eu_fence_buffer_objects(&ticket, &res, fence);
	if (old_bo != new_bo)
592
		nouveau_bo_unpin(old_bo);
593 594 595 596
	nouveau_fence_unref(&fence);
	return 0;

fail_unreserve:
597 598 599 600
	ttm_eu_backoff_reservation(&ticket, &res);
fail_unpin:
	mutex_unlock(&chan->cli->mutex);
	if (old_bo != new_bo)
601
		nouveau_bo_unpin(new_bo);
602 603 604 605 606 607 608 609 610
fail_free:
	kfree(s);
	return ret;
}

int
nouveau_finish_page_flip(struct nouveau_channel *chan,
			 struct nouveau_page_flip_state *ps)
{
611
	struct nouveau_fence_chan *fctx = chan->fence;
612 613
	struct nouveau_drm *drm = chan->drm;
	struct drm_device *dev = drm->dev;
614 615 616 617 618
	struct nouveau_page_flip_state *s;
	unsigned long flags;

	spin_lock_irqsave(&dev->event_lock, flags);

619
	if (list_empty(&fctx->flip)) {
620
		NV_ERROR(drm, "unexpected pageflip\n");
621 622 623 624
		spin_unlock_irqrestore(&dev->event_lock, flags);
		return -EINVAL;
	}

625
	s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
626 627
	if (s->event)
		drm_send_vblank_event(dev, -1, s->event);
628 629

	list_del(&s->head);
B
Ben Skeggs 已提交
630 631
	if (ps)
		*ps = *s;
632 633 634 635 636
	kfree(s);

	spin_unlock_irqrestore(&dev->event_lock, flags);
	return 0;
}
B
Ben Skeggs 已提交
637

638 639 640 641
int
nouveau_flip_complete(void *data)
{
	struct nouveau_channel *chan = data;
642
	struct nouveau_drm *drm = chan->drm;
643 644 645
	struct nouveau_page_flip_state state;

	if (!nouveau_finish_page_flip(chan, &state)) {
646 647
		if (nv_device(drm->device)->card_type < NV_50) {
			nv_set_crtc_base(drm->dev, state.crtc, state.offset +
648 649 650 651 652 653 654 655
					 state.y * state.pitch +
					 state.x * state.bpp / 8);
		}
	}

	return 0;
}

B
Ben Skeggs 已提交
656 657 658 659 660 661 662 663 664 665 666
int
nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
			    struct drm_mode_create_dumb *args)
{
	struct nouveau_bo *bo;
	int ret;

	args->pitch = roundup(args->width * (args->bpp / 8), 256);
	args->size = args->pitch * args->height;
	args->size = roundup(args->size, PAGE_SIZE);

667
	ret = nouveau_gem_new(dev, args->size, 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, &bo);
B
Ben Skeggs 已提交
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
	if (ret)
		return ret;

	ret = drm_gem_handle_create(file_priv, bo->gem, &args->handle);
	drm_gem_object_unreference_unlocked(bo->gem);
	return ret;
}

int
nouveau_display_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev,
			     uint32_t handle)
{
	return drm_gem_handle_delete(file_priv, handle);
}

int
nouveau_display_dumb_map_offset(struct drm_file *file_priv,
				struct drm_device *dev,
				uint32_t handle, uint64_t *poffset)
{
	struct drm_gem_object *gem;

	gem = drm_gem_object_lookup(dev, file_priv, handle);
	if (gem) {
		struct nouveau_bo *bo = gem->driver_private;
		*poffset = bo->bo.addr_space_offset;
		drm_gem_object_unreference_unlocked(gem);
		return 0;
	}

	return -ENOENT;
}