cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

radeon_cursor.c (11351B)


      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
     27#include <drm/drm_device.h>
     28#include <drm/radeon_drm.h>
     29
     30#include "radeon.h"
     31
     32static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
     33{
     34	struct radeon_device *rdev = crtc->dev->dev_private;
     35	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
     36	uint32_t cur_lock;
     37
     38	if (ASIC_IS_DCE4(rdev)) {
     39		cur_lock = RREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset);
     40		if (lock)
     41			cur_lock |= EVERGREEN_CURSOR_UPDATE_LOCK;
     42		else
     43			cur_lock &= ~EVERGREEN_CURSOR_UPDATE_LOCK;
     44		WREG32(EVERGREEN_CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
     45	} else if (ASIC_IS_AVIVO(rdev)) {
     46		cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
     47		if (lock)
     48			cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
     49		else
     50			cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
     51		WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
     52	} else {
     53		cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
     54		if (lock)
     55			cur_lock |= RADEON_CUR_LOCK;
     56		else
     57			cur_lock &= ~RADEON_CUR_LOCK;
     58		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
     59	}
     60}
     61
     62static void radeon_hide_cursor(struct drm_crtc *crtc)
     63{
     64	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
     65	struct radeon_device *rdev = crtc->dev->dev_private;
     66
     67	if (ASIC_IS_DCE4(rdev)) {
     68		WREG32_IDX(EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset,
     69			   EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
     70			   EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
     71	} else if (ASIC_IS_AVIVO(rdev)) {
     72		WREG32_IDX(AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset,
     73			   (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
     74	} else {
     75		u32 reg;
     76		switch (radeon_crtc->crtc_id) {
     77		case 0:
     78			reg = RADEON_CRTC_GEN_CNTL;
     79			break;
     80		case 1:
     81			reg = RADEON_CRTC2_GEN_CNTL;
     82			break;
     83		default:
     84			return;
     85		}
     86		WREG32_IDX(reg, RREG32_IDX(reg) & ~RADEON_CRTC_CUR_EN);
     87	}
     88}
     89
     90static void radeon_show_cursor(struct drm_crtc *crtc)
     91{
     92	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
     93	struct radeon_device *rdev = crtc->dev->dev_private;
     94
     95	if (radeon_crtc->cursor_out_of_bounds)
     96		return;
     97
     98	if (ASIC_IS_DCE4(rdev)) {
     99		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
    100		       upper_32_bits(radeon_crtc->cursor_addr));
    101		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
    102		       lower_32_bits(radeon_crtc->cursor_addr));
    103		WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
    104		WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
    105		       EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
    106		       EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
    107	} else if (ASIC_IS_AVIVO(rdev)) {
    108		if (rdev->family >= CHIP_RV770) {
    109			if (radeon_crtc->crtc_id)
    110				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH,
    111				       upper_32_bits(radeon_crtc->cursor_addr));
    112			else
    113				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH,
    114				       upper_32_bits(radeon_crtc->cursor_addr));
    115		}
    116
    117		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
    118		       lower_32_bits(radeon_crtc->cursor_addr));
    119		WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
    120		WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
    121		       (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
    122	} else {
    123		/* offset is from DISP(2)_BASE_ADDRESS */
    124		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
    125		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr);
    126
    127		switch (radeon_crtc->crtc_id) {
    128		case 0:
    129			WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
    130			break;
    131		case 1:
    132			WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
    133			break;
    134		default:
    135			return;
    136		}
    137
    138		WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
    139					  (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
    140			 ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
    141	}
    142}
    143
    144static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
    145{
    146	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
    147	struct radeon_device *rdev = crtc->dev->dev_private;
    148	int xorigin = 0, yorigin = 0;
    149	int w = radeon_crtc->cursor_width;
    150
    151	radeon_crtc->cursor_x = x;
    152	radeon_crtc->cursor_y = y;
    153
    154	if (ASIC_IS_AVIVO(rdev)) {
    155		/* avivo cursor are offset into the total surface */
    156		x += crtc->x;
    157		y += crtc->y;
    158	}
    159
    160	if (x < 0)
    161		xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
    162	if (y < 0)
    163		yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
    164
    165	if (!ASIC_IS_AVIVO(rdev)) {
    166		x += crtc->x;
    167		y += crtc->y;
    168	}
    169	DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
    170
    171	/* fixed on DCE6 and newer */
    172	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
    173		int i = 0;
    174		struct drm_crtc *crtc_p;
    175
    176		/*
    177		 * avivo cursor image can't end on 128 pixel boundary or
    178		 * go past the end of the frame if both crtcs are enabled
    179		 *
    180		 * NOTE: It is safe to access crtc->enabled of other crtcs
    181		 * without holding either the mode_config lock or the other
    182		 * crtc's lock as long as write access to this flag _always_
    183		 * grabs all locks.
    184		 */
    185		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
    186			if (crtc_p->enabled)
    187				i++;
    188		}
    189		if (i > 1) {
    190			int cursor_end, frame_end;
    191
    192			cursor_end = x + w;
    193			frame_end = crtc->x + crtc->mode.crtc_hdisplay;
    194			if (cursor_end >= frame_end) {
    195				w = w - (cursor_end - frame_end);
    196				if (!(frame_end & 0x7f))
    197					w--;
    198			} else if (cursor_end <= 0) {
    199				goto out_of_bounds;
    200			} else if (!(cursor_end & 0x7f)) {
    201				w--;
    202			}
    203			if (w <= 0) {
    204				goto out_of_bounds;
    205			}
    206		}
    207	}
    208
    209	if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
    210	    x >= (crtc->x + crtc->mode.hdisplay) ||
    211	    y >= (crtc->y + crtc->mode.vdisplay))
    212		goto out_of_bounds;
    213
    214	x += xorigin;
    215	y += yorigin;
    216
    217	if (ASIC_IS_DCE4(rdev)) {
    218		WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
    219		WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
    220		WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
    221		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
    222	} else if (ASIC_IS_AVIVO(rdev)) {
    223		WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
    224		WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
    225		WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
    226		       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
    227	} else {
    228		x -= crtc->x;
    229		y -= crtc->y;
    230
    231		if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
    232			y *= 2;
    233
    234		WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
    235		       (RADEON_CUR_LOCK
    236			| (xorigin << 16)
    237			| yorigin));
    238		WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
    239		       (RADEON_CUR_LOCK
    240			| (x << 16)
    241			| y));
    242		/* offset is from DISP(2)_BASE_ADDRESS */
    243		WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset,
    244		       radeon_crtc->cursor_addr - radeon_crtc->legacy_display_base_addr +
    245		       yorigin * 256);
    246	}
    247
    248	if (radeon_crtc->cursor_out_of_bounds) {
    249		radeon_crtc->cursor_out_of_bounds = false;
    250		if (radeon_crtc->cursor_bo)
    251			radeon_show_cursor(crtc);
    252	}
    253
    254	return 0;
    255
    256 out_of_bounds:
    257	if (!radeon_crtc->cursor_out_of_bounds) {
    258		radeon_hide_cursor(crtc);
    259		radeon_crtc->cursor_out_of_bounds = true;
    260	}
    261	return 0;
    262}
    263
    264int radeon_crtc_cursor_move(struct drm_crtc *crtc,
    265			    int x, int y)
    266{
    267	int ret;
    268
    269	radeon_lock_cursor(crtc, true);
    270	ret = radeon_cursor_move_locked(crtc, x, y);
    271	radeon_lock_cursor(crtc, false);
    272
    273	return ret;
    274}
    275
    276int radeon_crtc_cursor_set2(struct drm_crtc *crtc,
    277			    struct drm_file *file_priv,
    278			    uint32_t handle,
    279			    uint32_t width,
    280			    uint32_t height,
    281			    int32_t hot_x,
    282			    int32_t hot_y)
    283{
    284	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
    285	struct radeon_device *rdev = crtc->dev->dev_private;
    286	struct drm_gem_object *obj;
    287	struct radeon_bo *robj;
    288	int ret;
    289
    290	if (!handle) {
    291		/* turn off cursor */
    292		radeon_hide_cursor(crtc);
    293		obj = NULL;
    294		goto unpin;
    295	}
    296
    297	if ((width > radeon_crtc->max_cursor_width) ||
    298	    (height > radeon_crtc->max_cursor_height)) {
    299		DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
    300		return -EINVAL;
    301	}
    302
    303	obj = drm_gem_object_lookup(file_priv, handle);
    304	if (!obj) {
    305		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
    306		return -ENOENT;
    307	}
    308
    309	robj = gem_to_radeon_bo(obj);
    310	ret = radeon_bo_reserve(robj, false);
    311	if (ret != 0) {
    312		drm_gem_object_put(obj);
    313		return ret;
    314	}
    315	/* Only 27 bit offset for legacy cursor */
    316	ret = radeon_bo_pin_restricted(robj, RADEON_GEM_DOMAIN_VRAM,
    317				       ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
    318				       &radeon_crtc->cursor_addr);
    319	radeon_bo_unreserve(robj);
    320	if (ret) {
    321		DRM_ERROR("Failed to pin new cursor BO (%d)\n", ret);
    322		drm_gem_object_put(obj);
    323		return ret;
    324	}
    325
    326	radeon_lock_cursor(crtc, true);
    327
    328	if (width != radeon_crtc->cursor_width ||
    329	    height != radeon_crtc->cursor_height ||
    330	    hot_x != radeon_crtc->cursor_hot_x ||
    331	    hot_y != radeon_crtc->cursor_hot_y) {
    332		int x, y;
    333
    334		x = radeon_crtc->cursor_x + radeon_crtc->cursor_hot_x - hot_x;
    335		y = radeon_crtc->cursor_y + radeon_crtc->cursor_hot_y - hot_y;
    336
    337		radeon_crtc->cursor_width = width;
    338		radeon_crtc->cursor_height = height;
    339		radeon_crtc->cursor_hot_x = hot_x;
    340		radeon_crtc->cursor_hot_y = hot_y;
    341
    342		radeon_cursor_move_locked(crtc, x, y);
    343	}
    344
    345	radeon_show_cursor(crtc);
    346
    347	radeon_lock_cursor(crtc, false);
    348
    349unpin:
    350	if (radeon_crtc->cursor_bo) {
    351		struct radeon_bo *robj = gem_to_radeon_bo(radeon_crtc->cursor_bo);
    352		ret = radeon_bo_reserve(robj, false);
    353		if (likely(ret == 0)) {
    354			radeon_bo_unpin(robj);
    355			radeon_bo_unreserve(robj);
    356		}
    357		drm_gem_object_put(radeon_crtc->cursor_bo);
    358	}
    359
    360	radeon_crtc->cursor_bo = obj;
    361	return 0;
    362}
    363
    364/**
    365 * radeon_cursor_reset - Re-set the current cursor, if any.
    366 *
    367 * @crtc: drm crtc
    368 *
    369 * If the CRTC passed in currently has a cursor assigned, this function
    370 * makes sure it's visible.
    371 */
    372void radeon_cursor_reset(struct drm_crtc *crtc)
    373{
    374	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
    375
    376	if (radeon_crtc->cursor_bo) {
    377		radeon_lock_cursor(crtc, true);
    378
    379		radeon_cursor_move_locked(crtc, radeon_crtc->cursor_x,
    380					  radeon_crtc->cursor_y);
    381
    382		radeon_show_cursor(crtc);
    383
    384		radeon_lock_cursor(crtc, false);
    385	}
    386}