Subversion Repositories Kolibri OS

Rev

Rev 6105 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6105 serge 1
/*
2
 * Copyright 2008 Advanced Micro Devices, Inc.
3
 * Copyright 2008 Red Hat Inc.
4
 * Copyright 2009 Jerome Glisse.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
 * OTHER DEALINGS IN THE SOFTWARE.
23
 *
24
 * Authors: Dave Airlie
25
 *          Alex Deucher
26
 *          Jerome Glisse
27
 */
28
#include 
29
#include "radeon.h"
30
#include 
31
#include "radeon_asic.h"
32
 
33
#include 
34
#include 
35
 
36
#include "radeon_kfd.h"
37
 
38
#if defined(CONFIG_VGA_SWITCHEROO)
39
bool radeon_has_atpx(void);
40
#else
41
static inline bool radeon_has_atpx(void) { return false; }
42
#endif
43
 
44
 
45
/*
46
 * VBlank related functions.
47
 */
48
/**
49
 * radeon_get_vblank_counter_kms - get frame count
50
 *
51
 * @dev: drm dev pointer
6938 serge 52
 * @pipe: crtc to get the frame count from
6105 serge 53
 *
54
 * Gets the frame count on the requested crtc (all asics).
55
 * Returns frame count on success, -EINVAL on failure.
56
 */
6938 serge 57
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
6105 serge 58
{
59
	int vpos, hpos, stat;
60
	u32 count;
61
	struct radeon_device *rdev = dev->dev_private;
62
 
6938 serge 63
	if (pipe >= rdev->num_crtc) {
64
		DRM_ERROR("Invalid crtc %u\n", pipe);
6105 serge 65
		return -EINVAL;
66
	}
67
 
68
	/* The hw increments its frame counter at start of vsync, not at start
69
	 * of vblank, as is required by DRM core vblank counter handling.
70
	 * Cook the hw count here to make it appear to the caller as if it
71
	 * incremented at start of vblank. We measure distance to start of
72
	 * vblank in vpos. vpos therefore will be >= 0 between start of vblank
73
	 * and start of vsync, so vpos >= 0 means to bump the hw frame counter
74
	 * result by 1 to give the proper appearance to caller.
75
	 */
6938 serge 76
	if (rdev->mode_info.crtcs[pipe]) {
6105 serge 77
		/* Repeat readout if needed to provide stable result if
78
		 * we cross start of vsync during the queries.
79
		 */
80
		do {
6938 serge 81
			count = radeon_get_vblank_counter(rdev, pipe);
6105 serge 82
			/* Ask radeon_get_crtc_scanoutpos to return vpos as
83
			 * distance to start of vblank, instead of regular
84
			 * vertical scanout pos.
85
			 */
86
			stat = radeon_get_crtc_scanoutpos(
6938 serge 87
				dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
6105 serge 88
				&vpos, &hpos, NULL, NULL,
6938 serge 89
				&rdev->mode_info.crtcs[pipe]->base.hwmode);
90
		} while (count != radeon_get_vblank_counter(rdev, pipe));
6105 serge 91
 
92
		if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
93
		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
94
			DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
95
		}
96
		else {
6938 serge 97
			DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n",
98
				      pipe, vpos);
6105 serge 99
 
100
			/* Bump counter if we are at >= leading edge of vblank,
101
			 * but before vsync where vpos would turn negative and
102
			 * the hw counter really increments.
103
			 */
104
			if (vpos >= 0)
105
				count++;
106
		}
107
	}
108
	else {
109
	    /* Fallback to use value as is. */
6938 serge 110
	    count = radeon_get_vblank_counter(rdev, pipe);
6105 serge 111
	    DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
112
	}
113
 
114
	return count;
115
}
116
 
117
/**
118
 * radeon_enable_vblank_kms - enable vblank interrupt
119
 *
120
 * @dev: drm dev pointer
121
 * @crtc: crtc to enable vblank interrupt for
122
 *
123
 * Enable the interrupt on the requested crtc (all asics).
124
 * Returns 0 on success, -EINVAL on failure.
125
 */
126
int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
127
{
128
	struct radeon_device *rdev = dev->dev_private;
129
	unsigned long irqflags;
130
	int r;
131
 
132
	if (crtc < 0 || crtc >= rdev->num_crtc) {
133
		DRM_ERROR("Invalid crtc %d\n", crtc);
134
		return -EINVAL;
135
	}
136
 
137
	spin_lock_irqsave(&rdev->irq.lock, irqflags);
138
	rdev->irq.crtc_vblank_int[crtc] = true;
139
	r = radeon_irq_set(rdev);
140
	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
141
	return r;
142
}
143
 
144
/**
145
 * radeon_disable_vblank_kms - disable vblank interrupt
146
 *
147
 * @dev: drm dev pointer
148
 * @crtc: crtc to disable vblank interrupt for
149
 *
150
 * Disable the interrupt on the requested crtc (all asics).
151
 */
152
void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
153
{
154
	struct radeon_device *rdev = dev->dev_private;
155
	unsigned long irqflags;
156
 
157
	if (crtc < 0 || crtc >= rdev->num_crtc) {
158
		DRM_ERROR("Invalid crtc %d\n", crtc);
159
		return;
160
	}
161
 
162
	spin_lock_irqsave(&rdev->irq.lock, irqflags);
163
	rdev->irq.crtc_vblank_int[crtc] = false;
164
	radeon_irq_set(rdev);
165
	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
166
}
167
 
168
/**
169
 * radeon_get_vblank_timestamp_kms - get vblank timestamp
170
 *
171
 * @dev: drm dev pointer
172
 * @crtc: crtc to get the timestamp for
173
 * @max_error: max error
174
 * @vblank_time: time value
175
 * @flags: flags passed to the driver
176
 *
177
 * Gets the timestamp on the requested crtc based on the
178
 * scanout position.  (all asics).
179
 * Returns postive status flags on success, negative error on failure.
180
 */
181
int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
182
				    int *max_error,
183
				    struct timeval *vblank_time,
184
				    unsigned flags)
185
{
186
	struct drm_crtc *drmcrtc;
187
	struct radeon_device *rdev = dev->dev_private;
188
 
189
	if (crtc < 0 || crtc >= dev->num_crtcs) {
190
		DRM_ERROR("Invalid crtc %d\n", crtc);
191
		return -EINVAL;
192
	}
193
 
194
	/* Get associated drm_crtc: */
195
	drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
196
	if (!drmcrtc)
197
		return -EINVAL;
198
 
199
	/* Helper routine in DRM core does all the work: */
200
	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
201
						     vblank_time, flags,
202
						     &drmcrtc->hwmode);
203
}
204