sna_display.c 247 KB
Newer Older
1
2
/*
 * Copyright © 2007 Red Hat, Inc.
3
 * Copyright © 2013-2014 Intel Corporation
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
 *
 * 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:
 *    Dave Airlie <airlied@redhat.com>
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
36
#include <sys/mman.h>
37
38
39
40
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
41
#include <ctype.h>
42
#include <dirent.h>
43

44
45
#if HAVE_ALLOCA_H
#include <alloca.h>
Chris Wilson's avatar
Chris Wilson committed
46
47
48
49
50
51
52
53
54
#elif defined __GNUC__
#define alloca __builtin_alloca
#elif defined _AIX
#define alloca __alloca
#elif defined _MSC_VER
#include <malloc.h>
#define alloca _alloca
#else
void *alloca(size_t);
55
56
#endif

57
58
59
60
61
#define _PARSE_EDID_
/* Jump through a few hoops in order to fixup EDIDs */
#undef VERSION
#undef REVISION

62
63
64
#include "sna.h"
#include "sna_reg.h"
#include "fb/fbpict.h"
65
#include "intel_options.h"
66
#include "backlight.h"
67
68

#include <xf86Crtc.h>
69
#include <xf86RandR12.h>
70
#include <cursorstr.h>
71
72
73
74
75
76
77

#if XF86_CRTC_VERSION >= 3
#define HAS_GAMMA 1
#else
#define HAS_GAMMA 0
#endif

78
#include <X11/Xatom.h>
79
#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H)
80
#include <X11/extensions/dpmsconst.h>
81
82
83
84
#else
#define DPMSModeOn 0
#define DPMSModeOff 3
#endif
Chris Wilson's avatar
Chris Wilson committed
85
#include <xf86DDC.h> /* for xf86InterpretEDID */
86

87
88
#include <xf86drm.h>

89
90
91
92
93
#ifdef HAVE_VALGRIND
#include <valgrind.h>
#include <memcheck.h>
#endif

94
95
#define FAIL_CURSOR_IOCTL 0

96
97
98
99
100
/* Minor discrepancy between 32-bit/64-bit ABI in old kernels */
union compat_mode_get_connector{
	struct drm_mode_get_connector conn;
	uint32_t pad[20];
};
101

102
103
#define KNOWN_MODE_FLAGS ((1<<14)-1)

104
105
106
107
#ifndef MONITOR_EDID_COMPLETE_RAWDATA
#define MONITOR_EDID_COMPLETE_RAWDATA 1
#endif

108
109
110
111
#ifndef DEFAULT_DPI
#define DEFAULT_DPI 96
#endif

112
113
#define OUTPUT_STATUS_CACHE_MS 15000

114
115
#define DRM_MODE_PAGE_FLIP_ASYNC 0x02

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
#define DRM_PLANE_TYPE_OVERLAY 0
#define DRM_PLANE_TYPE_PRIMARY 1
#define DRM_PLANE_TYPE_CURSOR  2

#define LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xb9, struct local_mode_obj_get_properties)
struct local_mode_obj_get_properties {
	uint64_t props_ptr;
	uint64_t prop_values_ptr;
	uint32_t count_props;
	uint32_t obj_id;
	uint32_t obj_type;
	uint32_t pad;
};
#define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
struct local_mode_set_plane {
	uint32_t plane_id;
	uint32_t crtc_id;
	uint32_t fb_id; /* fb object contains surface format type */
	uint32_t flags;

	/* Signed dest location allows it to be partially off screen */
	int32_t crtc_x, crtc_y;
	uint32_t crtc_w, crtc_h;

	/* Source values are 16.16 fixed point */
	uint32_t src_x, src_y;
	uint32_t src_h, src_w;
};
#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)

struct local_mode_get_plane {
	uint32_t plane_id;

	uint32_t crtc_id;
	uint32_t fb_id;

	uint32_t possible_crtcs;
	uint32_t gamma_size;

	uint32_t count_format_types;
	uint64_t format_type_ptr;
};
#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)

struct local_mode_get_plane_res {
	uint64_t plane_id_ptr;
	uint64_t count_planes;
};
#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)

168
#if 1
169
170
171
172
173
#define __DBG DBG
#else
#define __DBG(x)
#endif

174
175
#define DBG_NATIVE_ROTATION ~0 /* minimum RR_Rotate_0 */

176
177
extern XF86ConfigPtr xf86configptr;

178
179
180
181
182
183
184
185
186
187
188
189
190
191
struct sna_cursor {
	struct sna_cursor *next;
	uint32_t *image;
	bool transformed;
	Rotation rotation;
	int ref;
	int size;
	int last_width;
	int last_height;
	unsigned handle;
	unsigned serial;
	unsigned alloc;
};

192
struct sna_crtc {
193
	struct sna_crtc_public public;
Chris Wilson's avatar
Chris Wilson committed
194
	uint32_t id;
195
	xf86CrtcPtr base;
196
	struct drm_mode_modeinfo kmode;
197
198
	PixmapPtr slave_pixmap;
	DamagePtr slave_damage;
199
	struct kgem_bo *bo, *shadow_bo, *client_bo, *cache_bo;
200
	struct sna_cursor *cursor;
Chris Wilson's avatar
Chris Wilson committed
201
	unsigned int last_cursor_size;
202
	uint32_t offset;
203
	bool shadow;
204
	bool fallback_shadow;
205
	bool transform;
206
	bool cursor_transform;
207
	bool hwcursor;
208
	bool flip_pending;
209

210
211
	struct pict_f_transform cursor_to_fb, fb_to_cursor;

212
	RegionRec crtc_damage;
213
214
	uint16_t shadow_bo_width, shadow_bo_height;

215
	uint32_t rotation;
216
217
218
219
220
221
222
	struct plane {
		uint32_t id;
		struct {
			uint32_t prop;
			uint32_t supported;
			uint32_t current;
		} rotation;
223
224
225
226
		struct {
			uint32_t prop;
			uint64_t values[2];
		} color_encoding;
227
228
229
		struct list link;
	} primary;
	struct list sprites;
230

231
232
	uint32_t mode_serial, flip_serial;

233
234
	uint32_t last_seq, wrap_seq;
	struct ust_msc swap;
235
236
237
238

	sna_flip_handler_t flip_handler;
	struct kgem_bo *flip_bo;
	void *flip_data;
239
240

	struct list shadow_link;
241
242
243
};

struct sna_property {
244
	drmModePropertyPtr kprop;
245
246
247
248
249
	int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
	Atom *atoms;
};

struct sna_output {
250
	xf86OutputPtr base;
251
252
	unsigned id;
	unsigned serial;
253

254
255
256
	unsigned possible_encoders;
	unsigned attached_encoders;

257
	unsigned int is_panel : 1;
258
	unsigned int add_default_modes : 1;
259
260
	int connector_type;
	int connector_type_id;
261

262
263
	uint32_t link_status_idx;

264
265
266
267
	uint32_t edid_idx;
	uint32_t edid_blob_id;
	uint32_t edid_len;
	void *edid_raw;
268
	void *fake_edid_raw;
269

270
	bool has_panel_limits;
271
272
273
	int panel_hdisplay;
	int panel_vdisplay;

274
	uint32_t dpms_id;
275
	uint8_t dpms_mode;
276
	struct backlight backlight;
277
	int backlight_active_level;
278

279
280
	uint32_t last_detect;
	uint32_t status;
281
	unsigned int hotplug_count;
282
	bool update_properties;
283
	bool reprobe;
284

285
286
287
288
289
290
291
	int num_modes;
	struct drm_mode_modeinfo *modes;

	int num_props;
	uint32_t *prop_ids;
	uint64_t *prop_values;
	struct sna_property *props;
292
293
};

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
enum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */
	OPTION_PREFERRED_MODE,
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,1,0)
	OPTION_ZOOM_MODES,
#endif
	OPTION_POSITION,
	OPTION_BELOW,
	OPTION_RIGHT_OF,
	OPTION_ABOVE,
	OPTION_LEFT_OF,
	OPTION_ENABLE,
	OPTION_DISABLE,
	OPTION_MIN_CLOCK,
	OPTION_MAX_CLOCK,
	OPTION_IGNORE,
	OPTION_ROTATE,
	OPTION_PANNING,
	OPTION_PRIMARY,
	OPTION_DEFAULT_MODES,
};

315
static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
Chris Wilson's avatar
Chris Wilson committed
316
static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
317
318
static bool sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc,
			  struct kgem_bo *bo, int x, int y);
Chris Wilson's avatar
Chris Wilson committed
319

320
321
322
323
324
static bool is_zaphod(ScrnInfoPtr scrn)
{
	return xf86IsEntityShared(scrn->entityList[0]);
}

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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
static bool
sna_zaphod_match(struct sna *sna, const char *output)
{
	const char *s, *colon;
	char t[20];
	unsigned int i = 0;

	s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
	if (s == NULL)
		return false;

	colon = strchr(s, ':');
	if (colon) /* Skip over the ZaphodPipes */
		s = colon + 1;

	do {
		/* match any outputs in a comma list, stopping at whitespace */
		switch (*s) {
		case '\0':
			t[i] = '\0';
			return strcmp(t, output) == 0;

		case ',':
			t[i] ='\0';
			if (strcmp(t, output) == 0)
				return TRUE;
			i = 0;
			break;

		case ' ':
		case '\t':
		case '\n':
		case '\r':
			break;

		default:
			t[i++] = *s;
			break;
		}

		s++;
	} while (i < sizeof(t));

	return false;
}

static unsigned
get_zaphod_crtcs(struct sna *sna)
{
	const char *str, *colon;
	unsigned crtcs = 0;

	str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
	if (str == NULL || (colon = strchr(str, ':')) == NULL) {
		DBG(("%s: no zaphod pipes, using screen number: %x\n",
		     __FUNCTION__,
		     sna->scrn->confScreen->device->screen));
		return 1 << sna->scrn->confScreen->device->screen;
	}

	DBG(("%s: ZaphodHeads='%s'\n", __FUNCTION__, str));
	while (str < colon) {
		char *end;
		unsigned crtc = strtoul(str, &end, 0);
		if (end == str)
			break;
		DBG(("%s: adding CRTC %d to zaphod pipes\n",
		     __FUNCTION__, crtc));
		crtcs |= 1 << crtc;
		str = end + 1;
	}
	DBG(("%s: ZaphodPipes=%x\n", __FUNCTION__, crtcs));
	return crtcs;
}

400
401
402
403
404
inline static unsigned count_to_mask(int x)
{
	return (1 << x) - 1;
}

405
406
407
408
409
410
411
static inline struct sna_output *to_sna_output(xf86OutputPtr output)
{
	return output->driver_private;
}

static inline int to_connector_id(xf86OutputPtr output)
{
412
413
	assert(to_sna_output(output));
	assert(to_sna_output(output)->id);
414
	return to_sna_output(output)->id;
415
416
}

417
418
419
420
static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
{
	return crtc->driver_private;
}
421

422
423
static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc)
{
424
	return crtc->public.flags >> 8 & 0xff;
425
426
427
428
}

static inline unsigned __sna_crtc_id(struct sna_crtc *crtc)
{
Chris Wilson's avatar
Chris Wilson committed
429
430
431
432
433
434
	return crtc->id;
}

uint32_t sna_crtc_id(xf86CrtcPtr crtc)
{
	return __sna_crtc_id(to_sna_crtc(crtc));
435
436
}

437
static inline bool event_pending(int fd)
438
439
{
	struct pollfd pfd;
440
	pfd.fd = fd;
441
442
443
444
	pfd.events = POLLIN;
	return poll(&pfd, 1, 0) == 1;
}

445
446
447
448
449
450
451
452
static bool sna_mode_wait_for_event(struct sna *sna)
{
	struct pollfd pfd;
	pfd.fd = sna->kgem.fd;
	pfd.events = POLLIN;
	return poll(&pfd, 1, -1) == 1;
}

453
static inline uint32_t fb_id(struct kgem_bo *bo)
454
{
455
	return bo->delta;
456
457
}

458
459
460
461
462
463
464
465
466
467
468
469
unsigned sna_crtc_count_sprites(xf86CrtcPtr crtc)
{
	struct plane *sprite;
	unsigned count;

	count = 0;
	list_for_each_entry(sprite, &to_sna_crtc(crtc)->sprites, link)
		count++;

	return count;
}

470
static struct plane *lookup_sprite(struct sna_crtc *crtc, unsigned idx)
471
{
472
473
474
475
476
477
478
479
480
481
482
483
484
	struct plane *sprite;

	list_for_each_entry(sprite, &crtc->sprites, link)
		if (idx-- == 0)
			return sprite;

	return NULL;
}

uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc, unsigned idx)
{
	struct plane *sprite;

485
	assert(to_sna_crtc(crtc));
486
487
488

	sprite = lookup_sprite(to_sna_crtc(crtc), idx);
	return sprite ? sprite->id : 0;
489
490
}

491
492
493
494
495
496
bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
{
	assert(to_sna_crtc(crtc));
	return to_sna_crtc(crtc)->transform;
}

497
static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc)
498
{
499
	bool record = true;
500
501
502
503
	if (seq < sna_crtc->last_seq) {
		if (sna_crtc->last_seq - seq > 0x40000000) {
			sna_crtc->wrap_seq++;
			DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n",
504
			     __FUNCTION__, __sna_crtc_pipe(sna_crtc),
505
			     sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
506
507
		} else {
			DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n",
508
			     __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq));
509
510

			record = false;
511
		}
512
	}
513
514
	*msc = (uint64_t)sna_crtc->wrap_seq << 32 | seq;
	return record;
515
516
517
518
519
520
}

uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
			      int tv_sec, int tv_usec, unsigned seq)
{
	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
521
522
	uint64_t msc;

523
	assert(sna_crtc);
524
525

	if (msc64(sna_crtc, seq, &msc)) {
526
		DBG(("%s: recording last swap on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
527
		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
528
529
530
531
532
		     tv_sec, tv_usec));
		sna_crtc->swap.tv_sec = tv_sec;
		sna_crtc->swap.tv_usec = tv_usec;
		sna_crtc->swap.msc = msc;
	} else {
533
		DBG(("%s: swap event on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
534
		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
535
536
537
538
		     tv_sec, tv_usec));
	}

	return msc;
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
}

const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
{
	static struct ust_msc zero;

	if (crtc == NULL) {
		return &zero;
	} else {
		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
		assert(sna_crtc);
		return &sna_crtc->swap;
	}
}

554
555
556
557
558
559
560
561
562
563
#ifndef NDEBUG
static void gem_close(int fd, uint32_t handle);
static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
			   int width, int height)
{
	struct drm_mode_fb_cmd info;

	assert(bo->scanout);

	VG_CLEAR(info);
564
	info.fb_id = fb_id(bo);
565
566
567
568

	assert(drmIoctl(kgem->fd, DRM_IOCTL_MODE_GETFB, &info) == 0);
	gem_close(kgem->fd, info.handle);

Chris Wilson's avatar
Chris Wilson committed
569
	assert(width <= info.width && height <= info.height);
570
}
571
572
#else
#define assert_scanout(k, b, w, h)
573
574
#endif

575
576
577
578
579
580
581
582
583
static void assert_crtc_fb(struct sna *sna, struct sna_crtc *crtc)
{
#ifndef NDEBUG
	struct drm_mode_crtc mode = { .crtc_id = __sna_crtc_id(crtc) };
	drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
	assert(mode.fb_id == fb_id(crtc->bo));
#endif
}

Chris Wilson's avatar
Chris Wilson committed
584
585
586
587
static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
		       int width, int height)
{
	ScrnInfoPtr scrn = sna->scrn;
Chris Wilson's avatar
Chris Wilson committed
588
	struct drm_mode_fb_cmd arg;
Chris Wilson's avatar
Chris Wilson committed
589

590
591
592
	if (!kgem_bo_is_fenced(&sna->kgem, bo))
		return 0;

593
	assert(bo->refcnt);
Chris Wilson's avatar
Chris Wilson committed
594
	assert(bo->proxy == NULL);
595
	assert(!bo->snoop);
596
	assert(8*bo->pitch >= width * scrn->bitsPerPixel);
597
	assert(height * bo->pitch <= kgem_bo_size(bo)); /* XXX crtc offset */
598
	if (fb_id(bo)) {
Chris Wilson's avatar
Chris Wilson committed
599
		DBG(("%s: reusing fb=%d for handle=%d\n",
600
		     __FUNCTION__, fb_id(bo), bo->handle));
601
		assert_scanout(&sna->kgem, bo, width, height);
602
		return fb_id(bo);
Chris Wilson's avatar
Chris Wilson committed
603
604
605
606
607
	}

	DBG(("%s: create fb %dx%d@%d/%d\n",
	     __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));

608
	assert(bo->tiling != I915_TILING_Y || sna->kgem.can_scanout_y);
609
	assert((bo->pitch & 63) == 0);
610
	assert(scrn->vtSema); /* must be master */
Chris Wilson's avatar
Chris Wilson committed
611
612
613
614
615
616
617
618
619

	VG_CLEAR(arg);
	arg.width = width;
	arg.height = height;
	arg.pitch = bo->pitch;
	arg.bpp = scrn->bitsPerPixel;
	arg.depth = scrn->depth;
	arg.handle = bo->handle;

620
	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
		/* Try again with the fancy version */
		struct local_mode_fb_cmd2 {
			uint32_t fb_id;
			uint32_t width, height;
			uint32_t pixel_format;
			uint32_t flags;

			uint32_t handles[4];
			uint32_t pitches[4]; /* pitch for each plane */
			uint32_t offsets[4]; /* offset of each plane */
			uint64_t modifiers[4];
		} f;
#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
		memset(&f, 0, sizeof(f));
		f.width = width;
		f.height = height;
		/* XXX interlaced */
		f.flags = 1 << 1; /* +modifiers */
		f.handles[0] = bo->handle;
		f.pitches[0] = bo->pitch;

		switch (bo->tiling) {
		case I915_TILING_NONE:
			break;
		case I915_TILING_X:
			/* I915_FORMAT_MOD_X_TILED */
			f.modifiers[0] = (uint64_t)1 << 56 | 1;
			break;
		case I915_TILING_Y:
			/* I915_FORMAT_MOD_X_TILED */
			f.modifiers[0] = (uint64_t)1 << 56 | 2;
			break;
		}

#define fourcc(a,b,c,d) ((a) | (b) << 8 | (c) << 16 | (d) << 24)
		switch (scrn->depth) {
		default:
			ERR(("%s: unhandled screen format, depth=%d\n",
			     __FUNCTION__, scrn->depth));
			goto fail;
		case 8:
			f.pixel_format = fourcc('C', '8', ' ', ' ');
			break;
		case 15:
			f.pixel_format = fourcc('X', 'R', '1', '5');
			break;
		case 16:
			f.pixel_format = fourcc('R', 'G', '1', '6');
			break;
		case 24:
			f.pixel_format = fourcc('X', 'R', '2', '4');
			break;
		case 30:
			f.pixel_format = fourcc('X', 'R', '3', '0');
			break;
		}
#undef fourcc

		if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) {
fail:
			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
				   "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
				   __FUNCTION__, width, height,
				   scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
			return 0;
		}

		arg.fb_id = f.fb_id;
Chris Wilson's avatar
Chris Wilson committed
689
	}
690
	assert(arg.fb_id != 0);
691
	bo->delta = arg.fb_id;
692
	DBG(("%s: attached fb=%d to handle=%d\n",
693
	     __FUNCTION__, bo->delta, arg.handle));
694

Chris Wilson's avatar
Chris Wilson committed
695
	bo->scanout = true;
696
	return bo->delta;
Chris Wilson's avatar
Chris Wilson committed
697
698
}

699
700
701
702
static uint32_t gem_create(int fd, int size)
{
	struct drm_i915_gem_create create;

703
704
	assert((size & 4095) == 0);

705
	VG_CLEAR(create);
706
	create.handle = 0;
707
	create.size = size;
708
709
710
711
712
	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);

	return create.handle;
}

713
714
715
static void *gem_mmap(int fd, int handle, int size)
{
	struct drm_i915_gem_mmap_gtt mmap_arg;
716
	struct drm_i915_gem_set_domain set_domain;
717
718
719
720
721
722
723
724
725
726
727
	void *ptr;

	VG_CLEAR(mmap_arg);
	mmap_arg.handle = handle;
	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
		return NULL;

	ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mmap_arg.offset);
	if (ptr == MAP_FAILED)
		return NULL;

728
729
730
731
732
733
734
735
736
	VG_CLEAR(set_domain);
	set_domain.handle = handle;
	set_domain.read_domains = I915_GEM_DOMAIN_GTT;
	set_domain.write_domain = I915_GEM_DOMAIN_GTT;
	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
		munmap(ptr, size);
		return NULL;
	}

737
738
739
	return ptr;
}

740
741
742
743
static void gem_close(int fd, uint32_t handle)
{
	struct drm_gem_close close;

744
	VG_CLEAR(close);
745
746
747
748
	close.handle = handle;
	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
}

749
750
751
#define BACKLIGHT_NAME             "Backlight"
#define BACKLIGHT_DEPRECATED_NAME  "BACKLIGHT"
static Atom backlight_atom, backlight_deprecated_atom;
752

753
754
755
756
757
758
759
760
761
762
763
#if HAVE_UDEV
static void
sna_backlight_uevent(int fd, void *closure)
{
	struct sna *sna = closure;
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
	int i;

	DBG(("%s()\n", __FUNCTION__));

	/* Drain the event queue */
764
	while (event_pending(fd)) {
765
766
		struct udev_device *dev;

767
		DBG(("%s: waiting for uevent\n", __FUNCTION__));
768
769
770
771
772
		dev = udev_monitor_receive_device(sna->mode.backlight_monitor);
		if (dev == NULL)
			break;

		udev_device_unref(dev);
773
	}
774
775

	/* Query all backlights for any changes */
776
	DBG(("%s: probing backlights for changes\n", __FUNCTION__));
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
	for (i = 0; i < sna->mode.num_real_output; i++) {
		xf86OutputPtr output = config->output[i];
		struct sna_output *sna_output = to_sna_output(output);
		int val;

		if (sna_output->dpms_mode != DPMSModeOn)
			continue;

		val = backlight_get(&sna_output->backlight);
		if (val < 0)
			continue;
		DBG(("%s(%s): backlight '%s' was %d, now %d\n",
		     __FUNCTION__, output->name, sna_output->backlight.iface,
		     sna_output->backlight_active_level, val));

		if (val == sna_output->backlight_active_level)
			continue;

		sna_output->backlight_active_level = val;

797
798
799
800
801
802
803
804
805
806
807
		if (output->randr_output) {
			DBG(("%s(%s): sending change notification\n", __FUNCTION__, output->name));
			RRChangeOutputProperty(output->randr_output,
					       backlight_atom, XA_INTEGER,
					       32, PropModeReplace, 1, &val,
					       TRUE, FALSE);
			RRChangeOutputProperty(output->randr_output,
					       backlight_deprecated_atom, XA_INTEGER,
					       32, PropModeReplace, 1, &val,
					       TRUE, FALSE);
		}
808
	}
809
	DBG(("%s: complete\n", __FUNCTION__));
810
811
812
813
814
815
816
}

static void sna_backlight_pre_init(struct sna *sna)
{
	struct udev *u;
	struct udev_monitor *mon;

817
818
819
820
#if !USE_BACKLIGHT
	return;
#endif

821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
	u = udev_new();
	if (!u)
		return;

	mon = udev_monitor_new_from_netlink(u, "udev");
	if (!mon)
		goto free_udev;

	if (udev_monitor_filter_add_match_subsystem_devtype(mon, "backlight", NULL))
		goto free_monitor;

	if (udev_monitor_enable_receiving(mon))
		goto free_monitor;

	sna->mode.backlight_handler =
		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
				      sna_backlight_uevent, sna);
	if (!sna->mode.backlight_handler)
		goto free_monitor;

	DBG(("%s: installed backlight monitor\n", __FUNCTION__));
	sna->mode.backlight_monitor = mon;

	return;

free_monitor:
	udev_monitor_unref(mon);
free_udev:
	udev_unref(u);
}

static void sna_backlight_drain_uevents(struct sna *sna)
{
	if (sna->mode.backlight_monitor == NULL)
		return;

857
	DBG(("%s()\n", __FUNCTION__));
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
	sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
			     sna);
}

static void sna_backlight_close(struct sna *sna)
{
	struct udev *u;

	if (sna->mode.backlight_handler == NULL)
		return;

	xf86RemoveGeneralHandler(sna->mode.backlight_handler);

	u = udev_monitor_get_udev(sna->mode.backlight_monitor);
	udev_monitor_unref(sna->mode.backlight_monitor);
	udev_unref(u);

	sna->mode.backlight_handler = NULL;
	sna->mode.backlight_monitor = NULL;
}
#else
static void sna_backlight_pre_init(struct sna *sna) { }
static void sna_backlight_drain_uevents(struct sna *sna) { }
static void sna_backlight_close(struct sna *sna) { }
#endif

884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
static void
sna_output_backlight_disable(struct sna_output *sna_output)
{
	xf86OutputPtr output = sna_output->base;

	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
		   "Failed to set backlight %s for output %s, disabling\n",
		   sna_output->backlight.iface, output->name);
	backlight_disable(&sna_output->backlight);
	if (output->randr_output) {
		RRDeleteOutputProperty(output->randr_output, backlight_atom);
		RRDeleteOutputProperty(output->randr_output, backlight_deprecated_atom);
	}
}

899
static int
900
sna_output_backlight_set(struct sna_output *sna_output, int level)
901
{
902
	int ret = 0;
903

904
	DBG(("%s(%s) level=%d, max=%d\n", __FUNCTION__,
905
	     sna_output->base->name, level, sna_output->backlight.max));
906

907
	if (backlight_set(&sna_output->backlight, level)) {
908
		sna_output_backlight_disable(sna_output);
909
		ret = -1;
910
	}
911
912
913
914
915

	/* Consume the uevent notification now so that we don't misconstrue
	 * the change latter when we wake up and the output is in a different
	 * state.
	 */
916
	sna_backlight_drain_uevents(to_sna(sna_output->base->scrn));
917
	return ret;
918
919
}

920
921
922
923
924
925
static bool
has_native_backlight(struct sna_output *sna_output)
{
	return sna_output->backlight.type == BL_RAW;
}

926
927
928
static void
sna_output_backlight_off(struct sna_output *sna_output)
{
929
930
931
932
933
934
935
	/* Trust the kernel to turn the native backlight off. However, we
	 * do explicitly turn the backlight back on (when we wake the output)
	 * just in case a third party turns it off!
	 */
	if (has_native_backlight(sna_output))
		return;

Chris Wilson's avatar
Chris Wilson committed
936
	DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
937
938
939
940
941
942
943
	backlight_off(&sna_output->backlight);
	sna_output_backlight_set(sna_output, 0);
}

static void
sna_output_backlight_on(struct sna_output *sna_output)
{
Chris Wilson's avatar
Chris Wilson committed
944
	DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
945
946
	sna_output_backlight_set(sna_output,
				 sna_output->backlight_active_level);
947
948
	if (backlight_on(&sna_output->backlight) < 0)
		sna_output_backlight_disable(sna_output);
949
950
}

951
952
953
954
static int
sna_output_backlight_get(xf86OutputPtr output)
{
	struct sna_output *sna_output = output->driver_private;
955
956
957
	int level = backlight_get(&sna_output->backlight);
	DBG(("%s(%s) level=%d, max=%d\n", __FUNCTION__,
	     output->name, level, sna_output->backlight.max));
958
959
960
	return level;
}

961
962
963
964
static char *
has_user_backlight_override(xf86OutputPtr output)
{
	struct sna *sna = to_sna(output->scrn);
965
	const char *str;
966
967
968
969
970

	str = xf86GetOptValString(sna->Options, OPTION_BACKLIGHT);
	if (str == NULL)
		return NULL;

Chris Wilson's avatar
Chris Wilson committed
971
	DBG(("%s(%s) requested %s\n", __FUNCTION__, output->name, str));
972
	if (*str == '\0')
Chris Wilson's avatar
Chris Wilson committed
973
		return (char *)str;
974

975
	if (!backlight_exists(str)) {
976
		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
977
			   "Unrecognised backlight control interface '%s'\n",
978
979
980
981
			   str);
		return NULL;
	}

982
	return strdup(str);
983
984
}

985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
static int get_device_minor(int fd)
{
	struct stat st;

	if (fstat(fd, &st) || !S_ISCHR(st.st_mode))
		return -1;

	return st.st_rdev & 0x63;
}

static const char * const sysfs_connector_types[] = {
	/* DRM_MODE_CONNECTOR_Unknown */	"Unknown",
	/* DRM_MODE_CONNECTOR_VGA */		"VGA",
	/* DRM_MODE_CONNECTOR_DVII */		"DVI-I",
	/* DRM_MODE_CONNECTOR_DVID */		"DVI-D",
	/* DRM_MODE_CONNECTOR_DVIA */		"DVI-A",
	/* DRM_MODE_CONNECTOR_Composite */	"Composite",
	/* DRM_MODE_CONNECTOR_SVIDEO */		"SVIDEO",
	/* DRM_MODE_CONNECTOR_LVDS */		"LVDS",
	/* DRM_MODE_CONNECTOR_Component */	"Component",
	/* DRM_MODE_CONNECTOR_9PinDIN */	"DIN",
	/* DRM_MODE_CONNECTOR_DisplayPort */	"DP",
	/* DRM_MODE_CONNECTOR_HDMIA */		"HDMI-A",
	/* DRM_MODE_CONNECTOR_HDMIB */		"HDMI-B",
	/* DRM_MODE_CONNECTOR_TV */		"TV",
	/* DRM_MODE_CONNECTOR_eDP */		"eDP",
	/* DRM_MODE_CONNECTOR_VIRTUAL */	"Virtual",
	/* DRM_MODE_CONNECTOR_DSI */		"DSI",
	/* DRM_MODE_CONNECTOR_DPI */		"DPI"
};

1016
static char *has_connector_backlight(xf86OutputPtr output)
1017
1018
1019
1020
1021
1022
1023
{
	struct sna_output *sna_output = output->driver_private;
	struct sna *sna = to_sna(output->scrn);
	char path[1024];
	DIR *dir;
	struct dirent *de;
	int minor, len;
1024
	char *str = NULL;
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040

	if (sna_output->connector_type >= ARRAY_SIZE(sysfs_connector_types))
		return NULL;

	minor = get_device_minor(sna->kgem.fd);
	if (minor < 0)
		return NULL;

	len = snprintf(path, sizeof(path),
		       "/sys/class/drm/card%d-%s-%d",
		       minor,
		       sysfs_connector_types[sna_output->connector_type],
		       sna_output->connector_type_id);
	DBG(("%s: lookup %s\n", __FUNCTION__, path));

	dir = opendir(path);
1041
1042
1043
	if (dir == NULL)
		return NULL;

1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
	while ((de = readdir(dir))) {
		struct stat st;

		if (*de->d_name == '.')
			continue;

		snprintf(path + len, sizeof(path) - len,
			 "/%s", de->d_name);

		if (stat(path, &st))
			continue;

		if (!S_ISDIR(st.st_mode))
			continue;

		DBG(("%s: testing %s as backlight\n",
		     __FUNCTION__, de->d_name));

		if (backlight_exists(de->d_name)) {
1063
			str = strdup(de->d_name); /* leak! */
1064
1065
1066
1067
1068
			break;
		}
	}

	closedir(dir);
1069
	return str;
1070
1071
}

1072
1073
1074
1075
static void
sna_output_backlight_init(xf86OutputPtr output)
{
	struct sna_output *sna_output = output->driver_private;
1076
	struct pci_device *pci;
1077
	MessageType from;
1078
1079
	char *best_iface;

1080
1081
1082
1083
#if !USE_BACKLIGHT
	return;
#endif

1084
1085
1086
1087
1088
1089
1090
	if (sna_output->is_panel) {
		from = X_CONFIG;
		best_iface = has_user_backlight_override(output);
		if (best_iface)
			goto done;
	}

1091
	best_iface = has_connector_backlight(output);
1092
1093
1094
	if (best_iface)
		goto done;

1095
1096
1097
	if (!sna_output->is_panel)
		return;

1098
1099
	/* XXX detect right backlight for multi-GPU/panels */
	from = X_PROBED;
1100
1101
1102
	pci = xf86GetPciInfoForEntity(to_sna(output->scrn)->pEnt->index);
	if (pci != NULL)
		best_iface = backlight_find_for_device(pci);
1103
1104

done:
1105
1106
	DBG(("%s(%s) opening backlight %s\n", __FUNCTION__,
	     output->name, best_iface ?: "none"));
1107
1108
	sna_output->backlight_active_level =
		backlight_open(&sna_output->backlight, best_iface);
1109
1110
	DBG(("%s(%s): initial backlight value %d\n",
	     __FUNCTION__, output->name, sna_output->backlight_active_level));
1111
1112
1113
	if (sna_output->backlight_active_level < 0)
		return;

1114
1115
1116
1117
	switch (sna_output->backlight.type) {
	case BL_FIRMWARE: best_iface = (char *)"firmware"; break;
	case BL_PLATFORM: best_iface = (char *)"platform"; break;
	case BL_RAW: best_iface = (char *)"raw"; break;
1118
	default: best_iface = (char *)"unknown"; break;
1119
	}
1120
	xf86DrvMsg(output->scrn->scrnIndex, from,
1121
1122
		   "Found backlight control interface %s (type '%s') for output %s\n",
		   sna_output->backlight.iface, best_iface, output->name);
1123
1124
}

1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(22, 0)
static inline int sigio_block(void)
{
	return 0;
}
static inline void sigio_unblock(int was_blocked)
{
	(void)was_blocked;
}
#elif XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
static inline int sigio_block(void)
{
	OsBlockSIGIO();
	return 0;
}
static inline void sigio_unblock(int was_blocked)
{
	OsReleaseSIGIO();
	(void)was_blocked;
}
#else
#include <xf86_OSproc.h>
static inline int sigio_block(void)
{
	return xf86BlockSIGIO();
}
static inline void sigio_unblock(int was_blocked)
{
	xf86UnblockSIGIO(was_blocked);
}
#endif

1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
static char *canonical_kmode_name(const struct drm_mode_modeinfo *kmode)
{
	char tmp[32], *buf;
	int len;

	len = sprintf(tmp, "%dx%d%s",
		      kmode->hdisplay, kmode->vdisplay,
		      kmode->flags & V_INTERLACE ? "i" : "");
	if ((unsigned)len >= sizeof(tmp))
		return NULL;

	buf = malloc(len + 1);
	if (buf == NULL)
		return NULL;

	return memcpy(buf, tmp, len + 1);
}

static char *get_kmode_name(const struct drm_mode_modeinfo *kmode)
{
	if (*kmode->name == '\0')
		return canonical_kmode_name(kmode);

	return strdup(kmode->name);
}

1183
static DisplayModePtr
1184
mode_from_kmode(ScrnInfoPtr scrn,
1185
1186
		const struct drm_mode_modeinfo *kmode,
		DisplayModePtr mode)
1187
{
1188
1189
1190
1191
1192
1193
	DBG(("kmode: %s, clock=%d, %d %d %d %d %d, %d %d %d %d %d, flags=%x, type=%x\n",
	     kmode->name, kmode->clock,
	     kmode->hdisplay, kmode->hsync_start, kmode->hsync_end, kmode->htotal, kmode->hskew,
	     kmode->vdisplay, kmode->vsync_start, kmode->vsync_end, kmode->vtotal, kmode->vscan,
	     kmode->flags, kmode->type));

1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
	mode->status = MODE_OK;

	mode->Clock = kmode->clock;

	mode->HDisplay = kmode->hdisplay;
	mode->HSyncStart = kmode->hsync_start;
	mode->HSyncEnd = kmode->hsync_end;
	mode->HTotal = kmode->htotal;
	mode->HSkew = kmode->hskew;

	mode->VDisplay = kmode->vdisplay;
	mode->VSyncStart = kmode->vsync_start;
	mode->VSyncEnd = kmode->vsync_end;
	mode->VTotal = kmode->vtotal;
	mode->VScan = kmode->vscan;

1210
	mode->VRefresh = kmode->vrefresh;
1211
	mode->Flags = kmode->flags;
1212
	mode->name = get_kmode_name(kmode);
1213
1214
1215
1216
1217
1218

	if (kmode->type & DRM_MODE_TYPE_DRIVER)
		mode->type = M_T_DRIVER;
	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
		mode->type |= M_T_PREFERRED;

1219
1220
1221
	if (mode->status == MODE_OK && kmode->flags & ~KNOWN_MODE_FLAGS)
		mode->status = MODE_BAD; /* unknown flags => unhandled */

1222
1223
	xf86SetModeCrtc(mode, scrn->adjustFlags);
	return mode;
1224
1225
1226
}

static void
1227
mode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode)
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
{
	memset(kmode, 0, sizeof(*kmode));

	kmode->clock = mode->Clock;
	kmode->hdisplay = mode->HDisplay;
	kmode->hsync_start = mode->HSyncStart;
	kmode->hsync_end = mode->HSyncEnd;
	kmode->htotal = mode->HTotal;
	kmode->hskew = mode->HSkew;

	kmode->vdisplay = mode->VDisplay;
	kmode->vsync_start = mode->VSyncStart;
	kmode->vsync_end = mode->VSyncEnd;
	kmode->vtotal = mode->VTotal;
	kmode->vscan = mode->VScan;

1244
	kmode->vrefresh = mode->VRefresh;
1245
	kmode->flags = mode->Flags;
1246
1247
1248
1249
1250
	if (mode->name)
		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
}

1251
1252
1253
static void
sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
{
1254
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1255
1256
	/* All attached outputs are valid, so update our timestamps */
	unsigned now = GetTimeInMillis();
1257
1258
	int i;

1259
	assert(to_sna_crtc(crtc));
1260
	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
1261

1262
1263
1264
1265
1266
1267
1268
	/* DPMS handling by the kernel is inconsistent, so after setting a
	 * mode on an output presume that we intend for it to be on, or that
	 * the kernel will force it on.
	 *
	 * So force DPMS to be on for all connected outputs, and restore
	 * the backlight.
	 */
1269
1270
	for (i = 0; i < config->num_output; i++) {
		xf86OutputPtr output = config->output[i];
1271
1272
1273
1274

		if (output->crtc != crtc)
			continue;

1275
		__sna_output_dpms(output, DPMSModeOn, false);
1276
1277
		if (to_sna_output(output)->last_detect)
			to_sna_output(output)->last_detect = now;
1278
	}
1279

1280
1281
1282
#if XF86_CRTC_VERSION >= 3
	crtc->active = TRUE;
#endif
1283
1284
}

1285
1286
1287
1288
1289
1290
static void
sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
{
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
	int i;

1291
	assert(to_sna_crtc(crtc));
1292
	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306

	/* DPMS handling by the kernel is inconsistent, so after setting a
	 * mode on an output presume that we intend for it to be on, or that
	 * the kernel will force it on.
	 *
	 * So force DPMS to be on for all connected outputs, and restore
	 * the backlight.
	 */
	for (i = 0; i < config->num_output; i++) {
		xf86OutputPtr output = config->output[i];

		if (output->crtc != crtc)
			continue;

1307
		__sna_output_dpms(output, DPMSModeOff, false);
1308
1309
1310
	}
}

1311
static unsigned
1312
rotation_reflect(unsigned rotation)
1313
{
1314
	unsigned other_bits;
1315

1316
1317
	/* paranoia for future extensions */
	other_bits = rotation & ~RR_Rotate_All;
1318

1319
1320
	/* flip the reflection to compensate for reflecting the rotation */
	other_bits ^= RR_Reflect_X | RR_Reflect_Y;
1321

1322
1323
1324
1325
1326
1327
1328
1329
	/* Reflect the screen by rotating the rotation bit,
	 * which has to have at least RR_Rotate_0 set. This allows
	 * us to reflect any of the rotation bits, not just 0.
	 */
	rotation &= RR_Rotate_All;
	assert(rotation);
	rotation <<= 2; /* RR_Rotate_0 -> RR_Rotate_180 etc */
	rotation |= rotation >> 4; /* RR_Rotate_270' to RR_Rotate_90 */
1330
1331
	rotation &= RR_Rotate_All;
	assert(rotation);
1332

1333
1334
	return rotation | other_bits;
}
1335

Chris Wilson's avatar