aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_cursor.c
diff options
context:
space:
mode:
authorJerome Glisse <jglisse@redhat.com>2009-06-05 08:42:42 -0400
committerDave Airlie <airlied@redhat.com>2009-06-14 22:01:53 -0400
commit771fe6b912fca54f03e8a72eb63058b582775362 (patch)
tree58aa5469ba8058c2b564d50807395ad6cd7bd7e4 /drivers/gpu/drm/radeon/radeon_cursor.c
parentba4e7d973dd09b66912ac4c0856add8b0703a997 (diff)
drm/radeon: introduce kernel modesetting for radeon hardware
Add kernel modesetting support to radeon driver, use the ttm memory manager to manage memory and DRM/GEM to provide userspace API. In order to avoid backward compatibility issue and to allow clean design and code the radeon kernel modesetting use different code path than old radeon/drm driver. When kernel modesetting is enabled the IOCTL of radeon/drm driver are considered as invalid and an error message is printed in the log and they return failure. KMS enabled userspace will use new API to talk with the radeon/drm driver. The new API provide functions to create/destroy/share/mmap buffer object which are then managed by the kernel memory manager (here TTM). In order to submit command to the GPU the userspace provide a buffer holding the command stream, along this buffer userspace have to provide a list of buffer object used by the command stream. The kernel radeon driver will then place buffer in GPU accessible memory and will update command stream to reflect the position of the different buffers. The kernel will also perform security check on command stream provided by the user, we want to catch and forbid any illegal use of the GPU such as DMA into random system memory or into memory not owned by the process supplying the command stream. This part of the code is still incomplete and this why we propose that patch as a staging driver addition, future security might forbid current experimental userspace to run. This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX (radeon up to X1950). Works is underway to provide support for R6XX, R7XX and newer hardware (radeon from HD2XXX to HD4XXX). Authors: Jerome Glisse <jglisse@redhat.com> Dave Airlie <airlied@redhat.com> Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_cursor.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
new file mode 100644
index 00000000000..5232441f119
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -0,0 +1,252 @@
1/*
2 * Copyright 2007-8 Advanced Micro Devices, Inc.
3 * Copyright 2008 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: Dave Airlie
24 * Alex Deucher
25 */
26#include "drmP.h"
27#include "radeon_drm.h"
28#include "radeon.h"
29
30#define CURSOR_WIDTH 64
31#define CURSOR_HEIGHT 64
32
33static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
34{
35 struct radeon_device *rdev = crtc->dev->dev_private;
36 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
37 uint32_t cur_lock;
38
39 if (ASIC_IS_AVIVO(rdev)) {
40 cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
41 if (lock)
42 cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
43 else
44 cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
45 WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
46 } else {
47 cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
48 if (lock)
49 cur_lock |= RADEON_CUR_LOCK;
50 else
51 cur_lock &= ~RADEON_CUR_LOCK;
52 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
53 }
54}
55
56static void radeon_hide_cursor(struct drm_crtc *crtc)
57{
58 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
59 struct radeon_device *rdev = crtc->dev->dev_private;
60
61 if (ASIC_IS_AVIVO(rdev)) {
62 WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
63 WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
64 } else {
65 switch (radeon_crtc->crtc_id) {
66 case 0:
67 WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
68 break;
69 case 1:
70 WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
71 break;
72 default:
73 return;
74 }
75 WREG32_P(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
76 }
77}
78
79static void radeon_show_cursor(struct drm_crtc *crtc)
80{
81 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
82 struct radeon_device *rdev = crtc->dev->dev_private;
83
84 if (ASIC_IS_AVIVO(rdev)) {
85 WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
86 WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
87 (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
88 } else {
89 switch (radeon_crtc->crtc_id) {
90 case 0:
91 WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
92 break;
93 case 1:
94 WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
95 break;
96 default:
97 return;
98 }
99
100 WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
101 (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
102 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
103 }
104}
105
106static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
107 uint32_t gpu_addr)
108{
109 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
110 struct radeon_device *rdev = crtc->dev->dev_private;
111
112 if (ASIC_IS_AVIVO(rdev))
113 WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
114 else
115 /* offset is from DISP(2)_BASE_ADDRESS */
116 WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, gpu_addr);
117}
118
119int radeon_crtc_cursor_set(struct drm_crtc *crtc,
120 struct drm_file *file_priv,
121 uint32_t handle,
122 uint32_t width,
123 uint32_t height)
124{
125 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
126 struct drm_gem_object *obj;
127 uint64_t gpu_addr;
128 int ret;
129
130 if (!handle) {
131 /* turn off cursor */
132 radeon_hide_cursor(crtc);
133 obj = NULL;
134 goto unpin;
135 }
136
137 if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
138 DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
139 return -EINVAL;
140 }
141
142 radeon_crtc->cursor_width = width;
143 radeon_crtc->cursor_height = height;
144
145 obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
146 if (!obj) {
147 DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
148 return -EINVAL;
149 }
150
151 ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
152 if (ret)
153 goto fail;
154
155 radeon_lock_cursor(crtc, true);
156 /* XXX only 27 bit offset for legacy cursor */
157 radeon_set_cursor(crtc, obj, gpu_addr);
158 radeon_show_cursor(crtc);
159 radeon_lock_cursor(crtc, false);
160
161unpin:
162 if (radeon_crtc->cursor_bo) {
163 radeon_gem_object_unpin(radeon_crtc->cursor_bo);
164 mutex_lock(&crtc->dev->struct_mutex);
165 drm_gem_object_unreference(radeon_crtc->cursor_bo);
166 mutex_unlock(&crtc->dev->struct_mutex);
167 }
168
169 radeon_crtc->cursor_bo = obj;
170 return 0;
171fail:
172 mutex_lock(&crtc->dev->struct_mutex);
173 drm_gem_object_unreference(obj);
174 mutex_unlock(&crtc->dev->struct_mutex);
175
176 return 0;
177}
178
179int radeon_crtc_cursor_move(struct drm_crtc *crtc,
180 int x, int y)
181{
182 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
183 struct radeon_device *rdev = crtc->dev->dev_private;
184 int xorigin = 0, yorigin = 0;
185
186 if (x < 0)
187 xorigin = -x + 1;
188 if (y < 0)
189 yorigin = -y + 1;
190 if (xorigin >= CURSOR_WIDTH)
191 xorigin = CURSOR_WIDTH - 1;
192 if (yorigin >= CURSOR_HEIGHT)
193 yorigin = CURSOR_HEIGHT - 1;
194
195 radeon_lock_cursor(crtc, true);
196 if (ASIC_IS_AVIVO(rdev)) {
197 int w = radeon_crtc->cursor_width;
198 int i = 0;
199 struct drm_crtc *crtc_p;
200
201 /* avivo cursor are offset into the total surface */
202 x += crtc->x;
203 y += crtc->y;
204 DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
205
206 /* avivo cursor image can't end on 128 pixel boundry or
207 * go past the end of the frame if both crtcs are enabled
208 */
209 list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
210 if (crtc_p->enabled)
211 i++;
212 }
213 if (i > 1) {
214 int cursor_end, frame_end;
215
216 cursor_end = x - xorigin + w;
217 frame_end = crtc->x + crtc->mode.crtc_hdisplay;
218 if (cursor_end >= frame_end) {
219 w = w - (cursor_end - frame_end);
220 if (!(frame_end & 0x7f))
221 w--;
222 } else {
223 if (!(cursor_end & 0x7f))
224 w--;
225 }
226 if (w <= 0)
227 w = 1;
228 }
229
230 WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
231 ((xorigin ? 0 : x) << 16) |
232 (yorigin ? 0 : y));
233 WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
234 WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
235 ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
236 } else {
237 if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
238 y *= 2;
239
240 WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
241 (RADEON_CUR_LOCK
242 | (xorigin << 16)
243 | yorigin));
244 WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
245 (RADEON_CUR_LOCK
246 | ((xorigin ? 0 : x) << 16)
247 | (yorigin ? 0 : y)));
248 }
249 radeon_lock_cursor(crtc, false);
250
251 return 0;
252}