Home | History | Annotate | Line # | Download | only in radeon
radeon_cursor.c revision 1.1.1.1.2.2
      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 <drm/drmP.h>
     27 #include <drm/radeon_drm.h>
     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 }
    315