Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5078 serge 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 
27
#include 
28
#include "radeon.h"
29
 
30
static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
31
{
32
	struct radeon_device *rdev = crtc->dev->dev_private;
33
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
34
	uint32_t cur_lock;
35
 
36
	if (ASIC_IS_DCE4(rdev)) {
37
		cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
38
		if (lock)
39
			cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
40
		else
41
			cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
42
		WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
43
	} else if (ASIC_IS_AVIVO(rdev)) {
44
		cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
45
		if (lock)
46
			cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
47
		else
48
			cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
49
		WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
50
	} else {
51
		cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
52
		if (lock)
53
			cur_lock |= RADEON_CUR_LOCK;
54
		else
55
			cur_lock &= ~RADEON_CUR_LOCK;
56
		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
57
	}
58
}
59
 
60
static void radeon_hide_cursor(struct drm_crtc *crtc)
61
{
62
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
63
	struct radeon_device *rdev = crtc->dev->dev_private;
64
 
65
	if (ASIC_IS_DCE4(rdev)) {
66
		WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
67
			   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
68
		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
69
	} else if (ASIC_IS_AVIVO(rdev)) {
70
		WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
71
			   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
72
	} else {
73
		u32 reg;
74
		switch (radeon_crtc->crtc_id) {
75
		case 0:
76
			reg = RADEON_CRTC_GEN_CNTL;
77
			break;
78
		case 1:
79
			reg = RADEON_CRTC2_GEN_CNTL;
80
			break;
81
		default:
82
			return;
83
		}
84
		WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
85
	}
86
}
87
 
88
static void radeon_show_cursor(struct drm_crtc *crtc)
89
{
90
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
91
	struct radeon_device *rdev = crtc->dev->dev_private;
92
 
93
	if (ASIC_IS_DCE4(rdev)) {
94
		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
95
		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
96
		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
97
		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
98
	} else if (ASIC_IS_AVIVO(rdev)) {
99
		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
100
		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
101
		       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
102
	} else {
103
		switch (radeon_crtc->crtc_id) {
104
		case 0:
105
			WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
106
			break;
107
		case 1:
108
			WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
109
			break;
110
		default:
111
			return;
112
		}
113
 
114
		WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
115
					  (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
116
			 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
117
	}
118
}
119
 
120
static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
121
			      uint64_t gpu_addr)
122
{
123
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
124
	struct radeon_device *rdev = crtc->dev->dev_private;
125
 
126
	if (ASIC_IS_DCE4(rdev)) {
127
		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
128
		       upper_32_bits(gpu_addr));
129
		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
130
		       gpu_addr & 0xffffffff);
131
	} else if (ASIC_IS_AVIVO(rdev)) {
132
		if (rdev->family >= CHIP_RV770) {
133
			if (radeon_crtc->crtc_id)
134
				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
135
			else
136
				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
137
		}
138
		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
139
		       gpu_addr & 0xffffffff);
140
	} else {
141
		radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
142
		/* offset is from DISP(2)_BASE_ADDRESS */
143
		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
144
	}
145
}
146
 
147
int radeon_crtc_cursor_set(struct drm_crtc *crtc,
148
			   struct drm_file *file_priv,
149
			   uint32_t handle,
150
			   uint32_t width,
151
			   uint32_t height)
152
{
153
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
154
	struct radeon_device *rdev = crtc->dev->dev_private;
155
	struct drm_gem_object *obj;
156
	struct radeon_bo *robj;
157
	uint64_t gpu_addr;
158
	int ret;
159
 
160
	if (!handle) {
161
		/* turn off cursor */
162
		radeon_hide_cursor(crtc);
163
		obj = NULL;
164
		goto unpin;
165
	}
166
 
167
	if ((width > radeon_crtc->max_cursor_width) ||
168
	    (height > radeon_crtc->max_cursor_height)) {
169
		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
170
		return -EINVAL;
171
	}
172
 
173
	obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
174
	if (!obj) {
175
		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
176
		return -ENOENT;
177
	}
178
 
179
	robj = gem_to_radeon_bo(obj);
180
	ret = radeon_bo_reserve(robj, false);
181
	if (unlikely(ret != 0))
182
		goto fail;
183
	/* Only 27 bit offset for legacy cursor */
184
	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
185
				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
186
				       &gpu_addr);
187
	radeon_bo_unreserve(robj);
188
	if (ret)
189
		goto fail;
190
 
191
	radeon_crtc->cursor_width = width;
192
	radeon_crtc->cursor_height = height;
193
 
194
	radeon_lock_cursor(crtc, true);
195
	radeon_set_cursor(crtc, obj, gpu_addr);
196
	radeon_show_cursor(crtc);
197
	radeon_lock_cursor(crtc, false);
198
 
199
unpin:
200
	if (radeon_crtc->cursor_bo) {
201
		robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
202
		ret = radeon_bo_reserve(robj, false);
203
		if (likely(ret == 0)) {
204
			radeon_bo_unpin(robj);
205
			radeon_bo_unreserve(robj);
206
		}
207
		drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
208
	}
209
 
210
	radeon_crtc->cursor_bo = obj;
211
	return 0;
212
fail:
213
	drm_gem_object_unreference_unlocked(obj);
214
 
215
	return ret;
216
}
217
 
218
int radeon_crtc_cursor_move(struct drm_crtc *crtc,
219
			    int x, int y)
220
{
221
	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
222
	struct radeon_device *rdev = crtc->dev->dev_private;
223
	int xorigin = 0, yorigin = 0;
224
	int w = radeon_crtc->cursor_width;
225
 
226
	if (ASIC_IS_AVIVO(rdev)) {
227
		/* avivo cursor are offset into the total surface */
228
		x += crtc->x;
229
		y += crtc->y;
230
	}
231
		DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
232
 
233
	if (x < 0) {
234
		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
235
		x = 0;
236
	}
237
	if (y < 0) {
238
		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
239
		y = 0;
240
	}
241
 
242
	/* fixed on DCE6 and newer */
243
	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
244
		int i = 0;
245
		struct drm_crtc *crtc_p;
246
 
247
		/*
248
		 * avivo cursor image can't end on 128 pixel boundary or
249
		 * go past the end of the frame if both crtcs are enabled
250
		 *
251
		 * NOTE: It is safe to access crtc->enabled of other crtcs
252
		 * without holding either the mode_config lock or the other
253
		 * crtc's lock as long as write access to this flag _always_
254
		 * grabs all locks.
255
		 */
256
		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
257
			if (crtc_p->enabled)
258
				i++;
259
		}
260
		if (i > 1) {
261
			int cursor_end, frame_end;
262
 
263
			cursor_end = x - xorigin + w;
264
			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
265
			if (cursor_end >= frame_end) {
266
				w = w - (cursor_end - frame_end);
267
				if (!(frame_end & 0x7f))
268
					w--;
269
			} else {
270
				if (!(cursor_end & 0x7f))
271
					w--;
272
			}
273
			if (w <= 0) {
274
				w = 1;
275
				cursor_end = x - xorigin + w;
276
				if (!(cursor_end & 0x7f)) {
277
					x--;
278
					WARN_ON_ONCE(x < 0);
279
				}
280
			}
281
		}
282
	}
283
 
284
	radeon_lock_cursor(crtc, true);
285
	if (ASIC_IS_DCE4(rdev)) {
286
		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
287
		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
288
		WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
289
		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
290
	} else if (ASIC_IS_AVIVO(rdev)) {
291
		WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
292
		WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
293
		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
294
		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
295
	} else {
296
		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
297
			y *= 2;
298
 
299
		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
300
		       (RADEON_CUR_LOCK
301
			| (xorigin << 16)
302
			| yorigin));
303
		WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
304
		       (RADEON_CUR_LOCK
305
			| (x << 16)
306
			| y));
307
		/* offset is from DISP(2)_BASE_ADDRESS */
308
		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
309
								      (yorigin * 256)));
310
	}
311
	radeon_lock_cursor(crtc, false);
312
 
313
	return 0;
314
}