Subversion Repositories Kolibri OS

Rev

Rev 5078 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4075 Serge 1
/**************************************************************************
2
 *
6296 serge 3
 * Copyright © 2011-2015 VMware, Inc., Palo Alto, CA., USA
4075 Serge 4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the
15
 * next paragraph) shall be included in all copies or substantial portions
16
 * of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 *
26
 **************************************************************************/
27
 
28
#include "vmwgfx_kms.h"
6296 serge 29
#include 
4075 Serge 30
 
31
 
32
#define vmw_crtc_to_sou(x) \
33
	container_of(x, struct vmw_screen_object_unit, base.crtc)
34
#define vmw_encoder_to_sou(x) \
35
	container_of(x, struct vmw_screen_object_unit, base.encoder)
36
#define vmw_connector_to_sou(x) \
37
	container_of(x, struct vmw_screen_object_unit, base.connector)
38
 
6296 serge 39
/**
40
 * struct vmw_kms_sou_surface_dirty - Closure structure for
41
 * blit surface to screen command.
42
 * @base: The base type we derive from. Used by vmw_kms_helper_dirty().
43
 * @left: Left side of bounding box.
44
 * @right: Right side of bounding box.
45
 * @top: Top side of bounding box.
46
 * @bottom: Bottom side of bounding box.
47
 * @dst_x: Difference between source clip rects and framebuffer coordinates.
48
 * @dst_y: Difference between source clip rects and framebuffer coordinates.
49
 * @sid: Surface id of surface to copy from.
50
 */
51
struct vmw_kms_sou_surface_dirty {
52
	struct vmw_kms_dirty base;
53
	s32 left, right, top, bottom;
54
	s32 dst_x, dst_y;
55
	u32 sid;
56
};
57
 
58
/*
59
 * SVGA commands that are used by this code. Please see the device headers
60
 * for explanation.
61
 */
62
struct vmw_kms_sou_readback_blit {
63
	uint32 header;
64
	SVGAFifoCmdBlitScreenToGMRFB body;
65
};
66
 
67
struct vmw_kms_sou_dmabuf_blit {
68
	uint32 header;
69
	SVGAFifoCmdBlitGMRFBToScreen body;
70
};
71
 
72
struct vmw_kms_sou_dirty_cmd {
73
	SVGA3dCmdHeader header;
74
	SVGA3dCmdBlitSurfaceToScreen body;
75
};
76
 
77
 
78
/*
79
 * Other structs.
80
 */
81
 
4075 Serge 82
struct vmw_screen_object_display {
83
	unsigned num_implicit;
84
 
85
	struct vmw_framebuffer *implicit_fb;
6296 serge 86
	SVGAFifoCmdDefineGMRFB cur;
87
	struct vmw_dma_buffer *pinned_gmrfb;
4075 Serge 88
};
89
 
90
/**
91
 * Display unit using screen objects.
92
 */
93
struct vmw_screen_object_unit {
94
	struct vmw_display_unit base;
95
 
96
	unsigned long buffer_size; /**< Size of allocated buffer */
97
	struct vmw_dma_buffer *buffer; /**< Backing store buffer */
98
 
99
	bool defined;
100
	bool active_implicit;
101
};
102
 
103
static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
104
{
6296 serge 105
	vmw_du_cleanup(&sou->base);
4075 Serge 106
	kfree(sou);
107
}
108
 
109
 
110
/*
111
 * Screen Object Display Unit CRTC functions
112
 */
113
 
114
static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
115
{
116
	vmw_sou_destroy(vmw_crtc_to_sou(crtc));
117
}
118
 
119
static void vmw_sou_del_active(struct vmw_private *vmw_priv,
6296 serge 120
			       struct vmw_screen_object_unit *sou)
4075 Serge 121
{
122
	struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
123
 
124
	if (sou->active_implicit) {
125
		if (--(ld->num_implicit) == 0)
126
			ld->implicit_fb = NULL;
127
		sou->active_implicit = false;
128
	}
129
}
130
 
131
static void vmw_sou_add_active(struct vmw_private *vmw_priv,
6296 serge 132
			       struct vmw_screen_object_unit *sou,
133
			       struct vmw_framebuffer *vfb)
4075 Serge 134
{
135
	struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
136
 
137
	BUG_ON(!ld->num_implicit && ld->implicit_fb);
138
 
139
	if (!sou->active_implicit && sou->base.is_implicit) {
140
		ld->implicit_fb = vfb;
141
		sou->active_implicit = true;
142
		ld->num_implicit++;
143
	}
144
}
145
 
146
/**
147
 * Send the fifo command to create a screen.
148
 */
5078 serge 149
static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
4075 Serge 150
			       struct vmw_screen_object_unit *sou,
151
			       uint32_t x, uint32_t y,
152
			       struct drm_display_mode *mode)
153
{
154
	size_t fifo_size;
155
 
156
	struct {
157
		struct {
158
			uint32_t cmdType;
159
		} header;
160
		SVGAScreenObject obj;
161
	} *cmd;
162
 
5078 serge 163
	BUG_ON(!sou->buffer);
4075 Serge 164
 
165
	fifo_size = sizeof(*cmd);
166
	cmd = vmw_fifo_reserve(dev_priv, fifo_size);
167
	/* The hardware has hung, nothing we can do about it here. */
168
	if (unlikely(cmd == NULL)) {
169
		DRM_ERROR("Fifo reserve failed.\n");
170
		return -ENOMEM;
171
	}
172
 
173
	memset(cmd, 0, fifo_size);
174
	cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN;
175
	cmd->obj.structSize = sizeof(SVGAScreenObject);
176
	cmd->obj.id = sou->base.unit;
177
	cmd->obj.flags = SVGA_SCREEN_HAS_ROOT |
178
		(sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
179
	cmd->obj.size.width = mode->hdisplay;
180
	cmd->obj.size.height = mode->vdisplay;
181
	if (sou->base.is_implicit) {
182
		cmd->obj.root.x = x;
183
		cmd->obj.root.y = y;
184
	} else {
185
		cmd->obj.root.x = sou->base.gui_x;
186
		cmd->obj.root.y = sou->base.gui_y;
187
	}
188
 
189
	/* Ok to assume that buffer is pinned in vram */
5078 serge 190
	vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
4075 Serge 191
	cmd->obj.backingStore.pitch = mode->hdisplay * 4;
192
 
193
	vmw_fifo_commit(dev_priv, fifo_size);
194
 
195
	sou->defined = true;
196
 
197
	return 0;
198
}
199
 
200
/**
201
 * Send the fifo command to destroy a screen.
202
 */
203
static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv,
204
				struct vmw_screen_object_unit *sou)
205
{
206
	size_t fifo_size;
207
	int ret;
208
 
209
	struct {
210
		struct {
211
			uint32_t cmdType;
212
		} header;
213
		SVGAFifoCmdDestroyScreen body;
214
	} *cmd;
215
 
216
	/* no need to do anything */
217
	if (unlikely(!sou->defined))
218
		return 0;
219
 
220
	fifo_size = sizeof(*cmd);
221
	cmd = vmw_fifo_reserve(dev_priv, fifo_size);
222
	/* the hardware has hung, nothing we can do about it here */
223
	if (unlikely(cmd == NULL)) {
224
		DRM_ERROR("Fifo reserve failed.\n");
225
		return -ENOMEM;
226
	}
227
 
228
	memset(cmd, 0, fifo_size);
229
	cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN;
230
	cmd->body.screenId = sou->base.unit;
231
 
232
	vmw_fifo_commit(dev_priv, fifo_size);
233
 
234
	/* Force sync */
235
	ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
236
	if (unlikely(ret != 0))
237
		DRM_ERROR("Failed to sync with HW");
238
	else
239
		sou->defined = false;
240
 
241
	return ret;
242
}
243
 
244
/**
245
 * Free the backing store.
246
 */
247
static void vmw_sou_backing_free(struct vmw_private *dev_priv,
248
				 struct vmw_screen_object_unit *sou)
249
{
6296 serge 250
	vmw_dmabuf_unreference(&sou->buffer);
4075 Serge 251
	sou->buffer_size = 0;
252
}
253
 
254
/**
255
 * Allocate the backing store for the buffer.
256
 */
257
static int vmw_sou_backing_alloc(struct vmw_private *dev_priv,
258
				 struct vmw_screen_object_unit *sou,
259
				 unsigned long size)
260
{
261
	int ret;
262
 
263
	if (sou->buffer_size == size)
264
		return 0;
265
 
266
	if (sou->buffer)
267
		vmw_sou_backing_free(dev_priv, sou);
268
 
269
	sou->buffer = kzalloc(sizeof(*sou->buffer), GFP_KERNEL);
270
	if (unlikely(sou->buffer == NULL))
271
		return -ENOMEM;
272
 
273
	/* After we have alloced the backing store might not be able to
274
	 * resume the overlays, this is preferred to failing to alloc.
275
	 */
6296 serge 276
	vmw_overlay_pause_all(dev_priv);
4075 Serge 277
	ret = vmw_dmabuf_init(dev_priv, sou->buffer, size,
278
			      &vmw_vram_ne_placement,
279
			      false, &vmw_dmabuf_bo_free);
6296 serge 280
	vmw_overlay_resume_all(dev_priv);
4075 Serge 281
 
282
	if (unlikely(ret != 0))
283
		sou->buffer = NULL; /* vmw_dmabuf_init frees on error */
284
	else
285
		sou->buffer_size = size;
286
 
287
	return ret;
288
}
289
 
290
static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
291
{
292
	struct vmw_private *dev_priv;
293
	struct vmw_screen_object_unit *sou;
294
	struct drm_connector *connector;
295
	struct drm_display_mode *mode;
296
	struct drm_encoder *encoder;
297
	struct vmw_framebuffer *vfb;
298
	struct drm_framebuffer *fb;
299
	struct drm_crtc *crtc;
300
	int ret = 0;
301
 
302
	if (!set)
303
		return -EINVAL;
304
 
305
	if (!set->crtc)
306
		return -EINVAL;
307
 
308
	/* get the sou */
309
	crtc = set->crtc;
310
	sou = vmw_crtc_to_sou(crtc);
311
	vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL;
312
	dev_priv = vmw_priv(crtc->dev);
313
 
314
	if (set->num_connectors > 1) {
6296 serge 315
		DRM_ERROR("Too many connectors\n");
4075 Serge 316
		return -EINVAL;
317
	}
318
 
319
	if (set->num_connectors == 1 &&
320
	    set->connectors[0] != &sou->base.connector) {
6296 serge 321
		DRM_ERROR("Connector doesn't match %p %p\n",
4075 Serge 322
			set->connectors[0], &sou->base.connector);
323
		return -EINVAL;
324
	}
325
 
326
	/* sou only supports one fb active at the time */
327
	if (sou->base.is_implicit &&
328
	    dev_priv->sou_priv->implicit_fb && vfb &&
329
	    !(dev_priv->sou_priv->num_implicit == 1 &&
330
	      sou->active_implicit) &&
331
	    dev_priv->sou_priv->implicit_fb != vfb) {
332
		DRM_ERROR("Multiple framebuffers not supported\n");
333
		return -EINVAL;
334
	}
335
 
336
	/* since they always map one to one these are safe */
337
	connector = &sou->base.connector;
338
	encoder = &sou->base.encoder;
339
 
340
	/* should we turn the crtc off */
341
	if (set->num_connectors == 0 || !set->mode || !set->fb) {
342
		ret = vmw_sou_fifo_destroy(dev_priv, sou);
343
		/* the hardware has hung don't do anything more */
344
		if (unlikely(ret != 0))
345
			return ret;
346
 
347
		connector->encoder = NULL;
348
		encoder->crtc = NULL;
5078 serge 349
		crtc->primary->fb = NULL;
4075 Serge 350
		crtc->x = 0;
351
		crtc->y = 0;
4569 Serge 352
		crtc->enabled = false;
4075 Serge 353
 
354
		vmw_sou_del_active(dev_priv, sou);
355
 
356
		vmw_sou_backing_free(dev_priv, sou);
357
 
358
		return 0;
359
	}
360
 
361
 
362
	/* we now know we want to set a mode */
363
	mode = set->mode;
364
	fb = set->fb;
365
 
366
	if (set->x + mode->hdisplay > fb->width ||
367
	    set->y + mode->vdisplay > fb->height) {
368
		DRM_ERROR("set outside of framebuffer\n");
369
		return -EINVAL;
370
	}
371
 
6296 serge 372
	vmw_svga_enable(dev_priv);
4075 Serge 373
 
374
	if (mode->hdisplay != crtc->mode.hdisplay ||
375
	    mode->vdisplay != crtc->mode.vdisplay) {
376
		/* no need to check if depth is different, because backing
377
		 * store depth is forced to 4 by the device.
378
		 */
379
 
380
		ret = vmw_sou_fifo_destroy(dev_priv, sou);
381
		/* the hardware has hung don't do anything more */
382
		if (unlikely(ret != 0))
383
			return ret;
384
 
385
		vmw_sou_backing_free(dev_priv, sou);
386
	}
387
 
388
	if (!sou->buffer) {
389
		/* forced to depth 4 by the device */
390
		size_t size = mode->hdisplay * mode->vdisplay * 4;
391
		ret = vmw_sou_backing_alloc(dev_priv, sou, size);
392
		if (unlikely(ret != 0))
393
			return ret;
394
	}
395
 
396
	ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode);
397
	if (unlikely(ret != 0)) {
398
		/*
399
		 * We are in a bit of a situation here, the hardware has
400
		 * hung and we may or may not have a buffer hanging of
401
		 * the screen object, best thing to do is not do anything
402
		 * if we where defined, if not just turn the crtc of.
403
		 * Not what userspace wants but it needs to htfu.
404
		 */
405
		if (sou->defined)
406
			return ret;
407
 
408
		connector->encoder = NULL;
409
		encoder->crtc = NULL;
5078 serge 410
		crtc->primary->fb = NULL;
4075 Serge 411
		crtc->x = 0;
412
		crtc->y = 0;
4569 Serge 413
		crtc->enabled = false;
4075 Serge 414
 
415
		return ret;
416
	}
417
 
418
	vmw_sou_add_active(dev_priv, sou, vfb);
419
 
420
	connector->encoder = encoder;
421
	encoder->crtc = crtc;
422
	crtc->mode = *mode;
5078 serge 423
	crtc->primary->fb = fb;
4075 Serge 424
	crtc->x = set->x;
425
	crtc->y = set->y;
4569 Serge 426
	crtc->enabled = true;
4075 Serge 427
 
428
	return 0;
429
}
430
 
6296 serge 431
/**
432
 * Returns if this unit can be page flipped.
433
 * Must be called with the mode_config mutex held.
434
 */
435
static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv,
436
					    struct drm_crtc *crtc)
437
{
438
	struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
439
 
440
	if (!sou->base.is_implicit)
441
		return true;
442
 
443
	if (dev_priv->sou_priv->num_implicit != 1)
444
		return false;
445
 
446
	return true;
447
}
448
 
449
/**
450
 * Update the implicit fb to the current fb of this crtc.
451
 * Must be called with the mode_config mutex held.
452
 */
453
static void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv,
454
				       struct drm_crtc *crtc)
455
{
456
	struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc);
457
 
458
	BUG_ON(!sou->base.is_implicit);
459
 
460
	dev_priv->sou_priv->implicit_fb =
461
		vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
462
}
4075 Serge 463
static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
464
	.save = vmw_du_crtc_save,
465
	.restore = vmw_du_crtc_restore,
466
//   .cursor_set = vmw_du_crtc_cursor_set,
467
//   .cursor_move = vmw_du_crtc_cursor_move,
468
	.gamma_set = vmw_du_crtc_gamma_set,
469
	.destroy = vmw_sou_crtc_destroy,
470
	.set_config = vmw_sou_crtc_set_config,
471
//   .page_flip = vmw_du_page_flip,
472
};
473
 
474
/*
475
 * Screen Object Display Unit encoder functions
476
 */
477
 
478
static void vmw_sou_encoder_destroy(struct drm_encoder *encoder)
479
{
480
	vmw_sou_destroy(vmw_encoder_to_sou(encoder));
481
}
482
 
483
static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
484
	.destroy = vmw_sou_encoder_destroy,
485
};
486
 
487
/*
488
 * Screen Object Display Unit connector functions
489
 */
490
 
491
static void vmw_sou_connector_destroy(struct drm_connector *connector)
492
{
493
	vmw_sou_destroy(vmw_connector_to_sou(connector));
494
}
495
 
6296 serge 496
static struct drm_connector_funcs vmw_sou_connector_funcs = {
4075 Serge 497
	.dpms = vmw_du_connector_dpms,
498
	.save = vmw_du_connector_save,
499
	.restore = vmw_du_connector_restore,
500
	.detect = vmw_du_connector_detect,
501
	.fill_modes = vmw_du_connector_fill_modes,
502
	.set_property = vmw_du_connector_set_property,
503
	.destroy = vmw_sou_connector_destroy,
504
};
505
 
506
static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
507
{
508
	struct vmw_screen_object_unit *sou;
509
	struct drm_device *dev = dev_priv->dev;
510
	struct drm_connector *connector;
511
	struct drm_encoder *encoder;
512
	struct drm_crtc *crtc;
513
 
514
	sou = kzalloc(sizeof(*sou), GFP_KERNEL);
515
	if (!sou)
516
		return -ENOMEM;
517
 
518
	sou->base.unit = unit;
519
	crtc = &sou->base.crtc;
520
	encoder = &sou->base.encoder;
521
	connector = &sou->base.connector;
522
 
523
	sou->active_implicit = false;
524
 
525
	sou->base.pref_active = (unit == 0);
526
	sou->base.pref_width = dev_priv->initial_width;
527
	sou->base.pref_height = dev_priv->initial_height;
528
	sou->base.pref_mode = NULL;
529
	sou->base.is_implicit = true;
530
 
6296 serge 531
	drm_connector_init(dev, connector, &vmw_sou_connector_funcs,
4075 Serge 532
			   DRM_MODE_CONNECTOR_VIRTUAL);
533
	connector->status = vmw_du_connector_detect(connector, true);
534
 
535
	drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
536
			 DRM_MODE_ENCODER_VIRTUAL);
537
	drm_mode_connector_attach_encoder(connector, encoder);
538
	encoder->possible_crtcs = (1 << unit);
539
	encoder->possible_clones = 0;
540
 
5078 serge 541
	(void) drm_connector_register(connector);
542
 
4075 Serge 543
	drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs);
544
 
545
	drm_mode_crtc_set_gamma_size(crtc, 256);
546
 
547
	drm_object_attach_property(&connector->base,
548
				      dev->mode_config.dirty_info_property,
549
				      1);
5078 serge 550
 
4075 Serge 551
	return 0;
552
}
553
 
6296 serge 554
int vmw_kms_sou_init_display(struct vmw_private *dev_priv)
4075 Serge 555
{
556
	struct drm_device *dev = dev_priv->dev;
557
	int i, ret;
558
 
559
	if (dev_priv->sou_priv) {
560
		DRM_INFO("sou system already on\n");
561
		return -EINVAL;
562
	}
563
 
564
	if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) {
565
		DRM_INFO("Not using screen objects,"
566
			 " missing cap SCREEN_OBJECT_2\n");
567
		return -ENOSYS;
568
	}
569
 
570
	ret = -ENOMEM;
571
	dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL);
572
	if (unlikely(!dev_priv->sou_priv))
573
		goto err_no_mem;
574
 
575
	dev_priv->sou_priv->num_implicit = 0;
576
	dev_priv->sou_priv->implicit_fb = NULL;
577
 
6296 serge 578
	ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
579
	if (unlikely(ret != 0))
580
		goto err_free;
4075 Serge 581
 
582
	ret = drm_mode_create_dirty_info_property(dev);
583
	if (unlikely(ret != 0))
584
		goto err_vblank_cleanup;
585
 
586
	for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i)
587
		vmw_sou_init(dev_priv, i);
588
 
6296 serge 589
	dev_priv->active_display_unit = vmw_du_screen_object;
4075 Serge 590
 
6296 serge 591
	DRM_INFO("Screen Objects Display Unit initialized\n");
592
 
4075 Serge 593
	return 0;
594
 
595
err_vblank_cleanup:
6296 serge 596
	drm_vblank_cleanup(dev);
4075 Serge 597
err_free:
598
	kfree(dev_priv->sou_priv);
599
	dev_priv->sou_priv = NULL;
600
err_no_mem:
601
	return ret;
602
}
603
 
6296 serge 604
int vmw_kms_sou_close_display(struct vmw_private *dev_priv)
4075 Serge 605
{
606
	struct drm_device *dev = dev_priv->dev;
607
 
608
	if (!dev_priv->sou_priv)
609
		return -ENOSYS;
610
 
6296 serge 611
	drm_vblank_cleanup(dev);
4075 Serge 612
 
613
	kfree(dev_priv->sou_priv);
614
 
615
	return 0;
616
}
617
 
6296 serge 618
static int do_dmabuf_define_gmrfb(struct vmw_private *dev_priv,
619
				  struct vmw_framebuffer *framebuffer)
620
{
621
	struct vmw_dma_buffer *buf =
622
		container_of(framebuffer, struct vmw_framebuffer_dmabuf,
623
			     base)->buffer;
624
	int depth = framebuffer->base.depth;
625
	struct {
626
		uint32_t header;
627
		SVGAFifoCmdDefineGMRFB body;
628
	} *cmd;
629
 
630
	/* Emulate RGBA support, contrary to svga_reg.h this is not
631
	 * supported by hosts. This is only a problem if we are reading
632
	 * this value later and expecting what we uploaded back.
633
	 */
634
	if (depth == 32)
635
		depth = 24;
636
 
637
	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
638
	if (!cmd) {
639
		DRM_ERROR("Out of fifo space for dirty framebuffer command.\n");
640
		return -ENOMEM;
641
	}
642
 
643
	cmd->header = SVGA_CMD_DEFINE_GMRFB;
644
	cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel;
645
	cmd->body.format.colorDepth = depth;
646
	cmd->body.format.reserved = 0;
647
	cmd->body.bytesPerLine = framebuffer->base.pitches[0];
648
	/* Buffer is reserved in vram or GMR */
649
	vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr);
650
	vmw_fifo_commit(dev_priv, sizeof(*cmd));
651
 
652
	return 0;
653
}
654
 
4075 Serge 655
/**
6296 serge 656
 * vmw_sou_surface_fifo_commit - Callback to fill in and submit a
657
 * blit surface to screen command.
658
 *
659
 * @dirty: The closure structure.
660
 *
661
 * Fills in the missing fields in the command, and translates the cliprects
662
 * to match the destination bounding box encoded.
4075 Serge 663
 */
6296 serge 664
static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty)
4075 Serge 665
{
6296 serge 666
	struct vmw_kms_sou_surface_dirty *sdirty =
667
		container_of(dirty, typeof(*sdirty), base);
668
	struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
669
	s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x;
670
	s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y;
671
	size_t region_size = dirty->num_hits * sizeof(SVGASignedRect);
672
	SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
673
	int i;
4075 Serge 674
 
6296 serge 675
	cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN;
676
	cmd->header.size = sizeof(cmd->body) + region_size;
4075 Serge 677
 
6296 serge 678
	/*
679
	 * Use the destination bounding box to specify destination - and
680
	 * source bounding regions.
681
	 */
682
	cmd->body.destRect.left = sdirty->left;
683
	cmd->body.destRect.right = sdirty->right;
684
	cmd->body.destRect.top = sdirty->top;
685
	cmd->body.destRect.bottom = sdirty->bottom;
4075 Serge 686
 
6296 serge 687
	cmd->body.srcRect.left = sdirty->left + trans_x;
688
	cmd->body.srcRect.right = sdirty->right + trans_x;
689
	cmd->body.srcRect.top = sdirty->top + trans_y;
690
	cmd->body.srcRect.bottom = sdirty->bottom + trans_y;
691
 
692
	cmd->body.srcImage.sid = sdirty->sid;
693
	cmd->body.destScreenId = dirty->unit->unit;
694
 
695
	/* Blits are relative to the destination rect. Translate. */
696
	for (i = 0; i < dirty->num_hits; ++i, ++blit) {
697
		blit->left -= sdirty->left;
698
		blit->right -= sdirty->left;
699
		blit->top -= sdirty->top;
700
		blit->bottom -= sdirty->top;
701
	}
702
 
703
	vmw_fifo_commit(dirty->dev_priv, region_size + sizeof(*cmd));
704
 
705
	sdirty->left = sdirty->top = S32_MAX;
706
	sdirty->right = sdirty->bottom = S32_MIN;
4075 Serge 707
}
708
 
709
/**
6296 serge 710
 * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect.
711
 *
712
 * @dirty: The closure structure
713
 *
714
 * Encodes a SVGASignedRect cliprect and updates the bounding box of the
715
 * BLIT_SURFACE_TO_SCREEN command.
4075 Serge 716
 */
6296 serge 717
static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty)
4075 Serge 718
{
6296 serge 719
	struct vmw_kms_sou_surface_dirty *sdirty =
720
		container_of(dirty, typeof(*sdirty), base);
721
	struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd;
722
	SVGASignedRect *blit = (SVGASignedRect *) &cmd[1];
4075 Serge 723
 
6296 serge 724
	/* Destination rect. */
725
	blit += dirty->num_hits;
726
	blit->left = dirty->unit_x1;
727
	blit->top = dirty->unit_y1;
728
	blit->right = dirty->unit_x2;
729
	blit->bottom = dirty->unit_y2;
4075 Serge 730
 
6296 serge 731
	/* Destination bounding box */
732
	sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1);
733
	sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1);
734
	sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2);
735
	sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2);
736
 
737
	dirty->num_hits++;
4075 Serge 738
}
4080 Serge 739
 
6296 serge 740
/**
741
 * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer
742
 *
743
 * @dev_priv: Pointer to the device private structure.
744
 * @framebuffer: Pointer to the surface-buffer backed framebuffer.
745
 * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
746
 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
747
 * be NULL.
748
 * @srf: Pointer to surface to blit from. If NULL, the surface attached
749
 * to @framebuffer will be used.
750
 * @dest_x: X coordinate offset to align @srf with framebuffer coordinates.
751
 * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates.
752
 * @num_clips: Number of clip rects in @clips.
753
 * @inc: Increment to use when looping over @clips.
754
 * @out_fence: If non-NULL, will return a ref-counted pointer to a
755
 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
756
 * case the device has already synchronized.
757
 *
758
 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
759
 * interrupted.
760
 */
761
int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
762
				 struct vmw_framebuffer *framebuffer,
763
				 struct drm_clip_rect *clips,
764
				 struct drm_vmw_rect *vclips,
765
				 struct vmw_resource *srf,
766
				 s32 dest_x,
767
				 s32 dest_y,
768
				 unsigned num_clips, int inc,
769
				 struct vmw_fence_obj **out_fence)
770
{
771
	struct vmw_framebuffer_surface *vfbs =
772
		container_of(framebuffer, typeof(*vfbs), base);
773
	struct vmw_kms_sou_surface_dirty sdirty;
774
	int ret;
4080 Serge 775
 
6296 serge 776
	if (!srf)
777
		srf = &vfbs->surface->res;
778
 
779
	ret = vmw_kms_helper_resource_prepare(srf, true);
780
	if (ret)
781
		return ret;
782
 
783
	sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit;
784
	sdirty.base.clip = vmw_sou_surface_clip;
785
	sdirty.base.dev_priv = dev_priv;
786
	sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) +
787
	  sizeof(SVGASignedRect) * num_clips;
788
 
789
	sdirty.sid = srf->id;
790
	sdirty.left = sdirty.top = S32_MAX;
791
	sdirty.right = sdirty.bottom = S32_MIN;
792
	sdirty.dst_x = dest_x;
793
	sdirty.dst_y = dest_y;
794
 
795
	ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
796
				   dest_x, dest_y, num_clips, inc,
797
				   &sdirty.base);
798
	vmw_kms_helper_resource_finish(srf, out_fence);
799
 
800
	return ret;
801
}
802
 
803
/**
804
 * vmw_sou_dmabuf_fifo_commit - Callback to submit a set of readback clips.
805
 *
806
 * @dirty: The closure structure.
807
 *
808
 * Commits a previously built command buffer of readback clips.
809
 */
810
static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty)
4080 Serge 811
{
6296 serge 812
	vmw_fifo_commit(dirty->dev_priv,
813
			sizeof(struct vmw_kms_sou_dmabuf_blit) *
814
			dirty->num_hits);
815
}
4080 Serge 816
 
6296 serge 817
/**
818
 * vmw_sou_dmabuf_clip - Callback to encode a readback cliprect.
819
 *
820
 * @dirty: The closure structure
821
 *
822
 * Encodes a BLIT_GMRFB_TO_SCREEN cliprect.
823
 */
824
static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty)
825
{
826
	struct vmw_kms_sou_dmabuf_blit *blit = dirty->cmd;
4080 Serge 827
 
6296 serge 828
	blit += dirty->num_hits;
829
	blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN;
830
	blit->body.destScreenId = dirty->unit->unit;
831
	blit->body.srcOrigin.x = dirty->fb_x;
832
	blit->body.srcOrigin.y = dirty->fb_y;
833
	blit->body.destRect.left = dirty->unit_x1;
834
	blit->body.destRect.top = dirty->unit_y1;
835
	blit->body.destRect.right = dirty->unit_x2;
836
	blit->body.destRect.bottom = dirty->unit_y2;
837
	dirty->num_hits++;
838
}
4080 Serge 839
 
6296 serge 840
/**
841
 * vmw_kms_do_dmabuf_dirty - Dirty part of a dma-buffer backed framebuffer
842
 *
843
 * @dev_priv: Pointer to the device private structure.
844
 * @framebuffer: Pointer to the dma-buffer backed framebuffer.
845
 * @clips: Array of clip rects.
846
 * @num_clips: Number of clip rects in @clips.
847
 * @increment: Increment to use when looping over @clips.
848
 * @interruptible: Whether to perform waits interruptible if possible.
849
 * @out_fence: If non-NULL, will return a ref-counted pointer to a
850
 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
851
 * case the device has already synchronized.
852
 *
853
 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
854
 * interrupted.
855
 */
856
int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv,
857
				struct vmw_framebuffer *framebuffer,
858
				struct drm_clip_rect *clips,
859
				unsigned num_clips, int increment,
860
				bool interruptible,
861
				struct vmw_fence_obj **out_fence)
862
{
863
	struct vmw_dma_buffer *buf =
864
		container_of(framebuffer, struct vmw_framebuffer_dmabuf,
865
			     base)->buffer;
866
	struct vmw_kms_dirty dirty;
867
	int ret;
4080 Serge 868
 
6296 serge 869
	ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible,
870
					    false);
871
	if (ret)
872
		return ret;
873
 
874
	ret = do_dmabuf_define_gmrfb(dev_priv, framebuffer);
875
	if (unlikely(ret != 0))
876
		goto out_revert;
877
 
878
	dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit;
879
	dirty.clip = vmw_sou_dmabuf_clip;
880
	dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) *
881
		num_clips;
882
	ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, NULL,
883
				   0, 0, num_clips, increment, &dirty);
884
	vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL);
885
 
886
	return ret;
887
 
888
out_revert:
889
	vmw_kms_helper_buffer_revert(buf);
890
 
891
	return ret;
892
}
893
 
894
 
895
/**
896
 * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips.
897
 *
898
 * @dirty: The closure structure.
899
 *
900
 * Commits a previously built command buffer of readback clips.
901
 */
902
static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty)
4080 Serge 903
{
6296 serge 904
	vmw_fifo_commit(dirty->dev_priv,
905
			sizeof(struct vmw_kms_sou_readback_blit) *
906
			dirty->num_hits);
907
}
4080 Serge 908
 
6296 serge 909
/**
910
 * vmw_sou_readback_clip - Callback to encode a readback cliprect.
911
 *
912
 * @dirty: The closure structure
913
 *
914
 * Encodes a BLIT_SCREEN_TO_GMRFB cliprect.
915
 */
916
static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty)
917
{
918
	struct vmw_kms_sou_readback_blit *blit = dirty->cmd;
4080 Serge 919
 
6296 serge 920
	blit += dirty->num_hits;
921
	blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB;
922
	blit->body.srcScreenId = dirty->unit->unit;
923
	blit->body.destOrigin.x = dirty->fb_x;
924
	blit->body.destOrigin.y = dirty->fb_y;
925
	blit->body.srcRect.left = dirty->unit_x1;
926
	blit->body.srcRect.top = dirty->unit_y1;
927
	blit->body.srcRect.right = dirty->unit_x2;
928
	blit->body.srcRect.bottom = dirty->unit_y2;
929
	dirty->num_hits++;
930
}
4080 Serge 931
 
6296 serge 932
/**
933
 * vmw_kms_sou_readback - Perform a readback from the screen object system to
934
 * a dma-buffer backed framebuffer.
935
 *
936
 * @dev_priv: Pointer to the device private structure.
937
 * @file_priv: Pointer to a struct drm_file identifying the caller.
938
 * Must be set to NULL if @user_fence_rep is NULL.
939
 * @vfb: Pointer to the dma-buffer backed framebuffer.
940
 * @user_fence_rep: User-space provided structure for fence information.
941
 * Must be set to non-NULL if @file_priv is non-NULL.
942
 * @vclips: Array of clip rects.
943
 * @num_clips: Number of clip rects in @vclips.
944
 *
945
 * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
946
 * interrupted.
947
 */
948
int vmw_kms_sou_readback(struct vmw_private *dev_priv,
949
			 struct drm_file *file_priv,
950
			 struct vmw_framebuffer *vfb,
951
			 struct drm_vmw_fence_rep __user *user_fence_rep,
952
			 struct drm_vmw_rect *vclips,
953
			 uint32_t num_clips)
954
{
955
	struct vmw_dma_buffer *buf =
956
		container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer;
957
	struct vmw_kms_dirty dirty;
958
	int ret;
4080 Serge 959
 
6296 serge 960
	ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false);
961
	if (ret)
962
		return ret;
963
 
964
	ret = do_dmabuf_define_gmrfb(dev_priv, vfb);
965
	if (unlikely(ret != 0))
966
		goto out_revert;
967
 
968
	dirty.fifo_commit = vmw_sou_readback_fifo_commit;
969
	dirty.clip = vmw_sou_readback_clip;
970
	dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) *
971
		num_clips;
972
	ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips,
973
				   0, 0, num_clips, 1, &dirty);
974
	vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL,
975
				     user_fence_rep);
976
 
977
	return ret;
978
 
979
out_revert:
980
	vmw_kms_helper_buffer_revert(buf);
981
 
982
	return ret;
983
}
984
 
985
#if 0
986
#include 
987
extern display_t os_display;
988
 
4080 Serge 989
bool set_mode(struct drm_device *dev, struct drm_connector *connector,
990
              videomode_t *reqmode, bool strict)
991
{
992
    struct drm_display_mode  *mode = NULL, *tmpmode;
4111 Serge 993
    struct vmw_private *dev_priv = vmw_priv(dev);
4080 Serge 994
    struct vmw_screen_object_unit *sou;
995
    display_t *os_display;
996
 
997
    bool ret = false;
998
 
999
//    dbgprintf("width %d height %d vrefresh %d\n",
1000
//               reqmode->width, reqmode->height, reqmode->freq);
1001
 
1002
    list_for_each_entry(tmpmode, &connector->modes, head)
1003
    {
1004
        if( (drm_mode_width(tmpmode)    == reqmode->width)  &&
1005
            (drm_mode_height(tmpmode)   == reqmode->height) &&
1006
            (drm_mode_vrefresh(tmpmode) == reqmode->freq) )
1007
        {
1008
            mode = tmpmode;
1009
            goto do_set;
1010
        }
1011
    };
1012
 
1013
    if( (mode == NULL) && (strict == false) )
1014
    {
1015
        list_for_each_entry(tmpmode, &connector->modes, head)
1016
        {
1017
            if( (drm_mode_width(tmpmode)  == reqmode->width)  &&
1018
                (drm_mode_height(tmpmode) == reqmode->height) )
1019
            {
1020
                mode = tmpmode;
1021
                goto do_set;
1022
            }
1023
        };
1024
    };
1025
 
1026
do_set:
1027
 
1028
    if( mode != NULL )
1029
    {
1030
        struct drm_framebuffer   *fb;
1031
        struct drm_encoder       *encoder;
1032
        struct drm_crtc          *crtc;
1033
 
1034
//        char  con_edid[128];
1035
        const char *con_name;
1036
        const char *enc_name;
1037
 
1038
        encoder = connector->encoder;
1039
        crtc = encoder->crtc;
1040
 
1041
 
1042
//        fb = list_first_entry(&dev->mode_config.fb_kernel_list,
1043
//                              struct drm_framebuffer, filp_head);
1044
 
1045
//        memcpy(con_edid, connector->edid_blob_ptr->data, 128);
1046
 
1047
//        dbgprintf("Manufacturer: %s Model %x Serial Number %u\n",
1048
//        manufacturer_name(con_edid + 0x08),
1049
//        (unsigned short)(con_edid[0x0A] + (con_edid[0x0B] << 8)),
1050
//        (unsigned int)(con_edid[0x0C] + (con_edid[0x0D] << 8)
1051
//            + (con_edid[0x0E] << 16) + (con_edid[0x0F] << 24)));
1052
 
1053
        con_name = drm_get_connector_name(connector);
1054
        enc_name = drm_get_encoder_name(encoder);
1055
 
1056
        dbgprintf("set mode %d %d connector %s encoder %s\n",
1057
                   mode->hdisplay, mode->vdisplay, con_name, enc_name);
1058
 
1059
        os_display = GetDisplay();
1060
 
1061
#if 0
1062
        sou = vmw_crtc_to_sou(crtc);
1063
        sou->defined = true;
1064
 
1065
        ret = vmw_sou_fifo_destroy(dev_priv, sou);
1066
        if (unlikely(ret != 0))
1067
            return ret;
1068
 
1069
        ret = vmw_sou_fifo_create(dev_priv, sou, 0, 0, mode);
1070
 
1071
#else   /*   sledgehammer  */
1072
 
1073
        vmw_write(dev_priv,SVGA_REG_WIDTH,  mode->hdisplay);
1074
        vmw_write(dev_priv,SVGA_REG_HEIGHT, mode->vdisplay);
1075
        vmw_write(dev_priv,SVGA_REG_BITS_PER_PIXEL, 32);
5078 serge 1076
        os_display->select_cursor(os_display->cursor);
4080 Serge 1077
        ret = 0;
1078
#endif
1079
        if (ret == 0)
1080
        {
1081
            os_display->width    = mode->hdisplay;
1082
            os_display->height   = mode->vdisplay;
1083
            os_display->pitch    = mode->hdisplay*4;
1084
            os_display->vrefresh = drm_mode_vrefresh(mode);
1085
 
1086
            sysSetScreen(os_display->width, os_display->height, os_display->pitch);
1087
 
1088
            dbgprintf("new mode %d x %d pitch %d\n",
1089
                       os_display->width, os_display->height, os_display->pitch);
1090
        }
1091
        else
1092
            DRM_ERROR("failed to set mode %d_%d on crtc %p\n",
1093
                       os_display->width, os_display->height, crtc);
1094
    }
1095
 
1096
    return ret;
1097
};
6296 serge 1098
#endif