Subversion Repositories Kolibri OS

Rev

Rev 6938 | 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
 
7146 serge 33
#include 
6105 serge 34
#include 
35
#include 
36
 
37
#include "radeon_kfd.h"
38
 
39
#if defined(CONFIG_VGA_SWITCHEROO)
40
bool radeon_has_atpx(void);
41
#else
42
static inline bool radeon_has_atpx(void) { return false; }
43
#endif
44
 
45
 
46
/*
47
 * VBlank related functions.
48
 */
49
/**
50
 * radeon_get_vblank_counter_kms - get frame count
51
 *
52
 * @dev: drm dev pointer
6938 serge 53
 * @pipe: crtc to get the frame count from
6105 serge 54
 *
55
 * Gets the frame count on the requested crtc (all asics).
56
 * Returns frame count on success, -EINVAL on failure.
57
 */
6938 serge 58
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
6105 serge 59
{
60
	int vpos, hpos, stat;
61
	u32 count;
62
	struct radeon_device *rdev = dev->dev_private;
63
 
6938 serge 64
	if (pipe >= rdev->num_crtc) {
65
		DRM_ERROR("Invalid crtc %u\n", pipe);
6105 serge 66
		return -EINVAL;
67
	}
68
 
69
	/* The hw increments its frame counter at start of vsync, not at start
70
	 * of vblank, as is required by DRM core vblank counter handling.
71
	 * Cook the hw count here to make it appear to the caller as if it
72
	 * incremented at start of vblank. We measure distance to start of
73
	 * vblank in vpos. vpos therefore will be >= 0 between start of vblank
74
	 * and start of vsync, so vpos >= 0 means to bump the hw frame counter
75
	 * result by 1 to give the proper appearance to caller.
76
	 */
6938 serge 77
	if (rdev->mode_info.crtcs[pipe]) {
6105 serge 78
		/* Repeat readout if needed to provide stable result if
79
		 * we cross start of vsync during the queries.
80
		 */
81
		do {
6938 serge 82
			count = radeon_get_vblank_counter(rdev, pipe);
6105 serge 83
			/* Ask radeon_get_crtc_scanoutpos to return vpos as
84
			 * distance to start of vblank, instead of regular
85
			 * vertical scanout pos.
86
			 */
87
			stat = radeon_get_crtc_scanoutpos(
6938 serge 88
				dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
6105 serge 89
				&vpos, &hpos, NULL, NULL,
6938 serge 90
				&rdev->mode_info.crtcs[pipe]->base.hwmode);
91
		} while (count != radeon_get_vblank_counter(rdev, pipe));
6105 serge 92
 
93
		if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
94
		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
95
			DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
96
		}
97
		else {
6938 serge 98
			DRM_DEBUG_VBL("crtc %u: dist from vblank start %d\n",
99
				      pipe, vpos);
6105 serge 100
 
101
			/* Bump counter if we are at >= leading edge of vblank,
102
			 * but before vsync where vpos would turn negative and
103
			 * the hw counter really increments.
104
			 */
105
			if (vpos >= 0)
106
				count++;
107
		}
108
	}
109
	else {
110
	    /* Fallback to use value as is. */
6938 serge 111
	    count = radeon_get_vblank_counter(rdev, pipe);
6105 serge 112
	    DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
113
	}
114
 
115
	return count;
116
}
117
 
118
/**
119
 * radeon_enable_vblank_kms - enable vblank interrupt
120
 *
121
 * @dev: drm dev pointer
122
 * @crtc: crtc to enable vblank interrupt for
123
 *
124
 * Enable the interrupt on the requested crtc (all asics).
125
 * Returns 0 on success, -EINVAL on failure.
126
 */
127
int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
128
{
129
	struct radeon_device *rdev = dev->dev_private;
130
	unsigned long irqflags;
131
	int r;
132
 
133
	if (crtc < 0 || crtc >= rdev->num_crtc) {
134
		DRM_ERROR("Invalid crtc %d\n", crtc);
135
		return -EINVAL;
136
	}
137
 
138
	spin_lock_irqsave(&rdev->irq.lock, irqflags);
139
	rdev->irq.crtc_vblank_int[crtc] = true;
140
	r = radeon_irq_set(rdev);
141
	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
142
	return r;
143
}
144
 
145
/**
146
 * radeon_disable_vblank_kms - disable vblank interrupt
147
 *
148
 * @dev: drm dev pointer
149
 * @crtc: crtc to disable vblank interrupt for
150
 *
151
 * Disable the interrupt on the requested crtc (all asics).
152
 */
153
void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
154
{
155
	struct radeon_device *rdev = dev->dev_private;
156
	unsigned long irqflags;
157
 
158
	if (crtc < 0 || crtc >= rdev->num_crtc) {
159
		DRM_ERROR("Invalid crtc %d\n", crtc);
160
		return;
161
	}
162
 
163
	spin_lock_irqsave(&rdev->irq.lock, irqflags);
164
	rdev->irq.crtc_vblank_int[crtc] = false;
165
	radeon_irq_set(rdev);
166
	spin_unlock_irqrestore(&rdev->irq.lock, irqflags);
167
}
168
 
169
/**
170
 * radeon_get_vblank_timestamp_kms - get vblank timestamp
171
 *
172
 * @dev: drm dev pointer
173
 * @crtc: crtc to get the timestamp for
174
 * @max_error: max error
175
 * @vblank_time: time value
176
 * @flags: flags passed to the driver
177
 *
178
 * Gets the timestamp on the requested crtc based on the
179
 * scanout position.  (all asics).
180
 * Returns postive status flags on success, negative error on failure.
181
 */
182
int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
183
				    int *max_error,
184
				    struct timeval *vblank_time,
185
				    unsigned flags)
186
{
187
	struct drm_crtc *drmcrtc;
188
	struct radeon_device *rdev = dev->dev_private;
189
 
190
	if (crtc < 0 || crtc >= dev->num_crtcs) {
191
		DRM_ERROR("Invalid crtc %d\n", crtc);
192
		return -EINVAL;
193
	}
194
 
195
	/* Get associated drm_crtc: */
196
	drmcrtc = &rdev->mode_info.crtcs[crtc]->base;
197
	if (!drmcrtc)
198
		return -EINVAL;
199
 
200
	/* Helper routine in DRM core does all the work: */
201
	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
202
						     vblank_time, flags,
203
						     &drmcrtc->hwmode);
204
}
205