PageRenderTime 104ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/gpu/drm/radeon/radeon_cursor.c

https://github.com/mstsirkin/linux
C | 288 lines | 226 code | 29 blank | 33 comment | 46 complexity | 2658800619669310cb3e7cbce4e0b25a MD5 | raw file
  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. #define CURSOR_WIDTH 64
  30. #define CURSOR_HEIGHT 64
  31. static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
  32. {
  33. struct radeon_device *rdev = crtc->dev->dev_private;
  34. struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  35. uint32_t cur_lock;
  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. static void radeon_hide_cursor(struct drm_crtc *crtc)
  60. {
  61. struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  62. struct radeon_device *rdev = crtc->dev->dev_private;
  63. if (ASIC_IS_DCE4(rdev)) {
  64. WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
  65. WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
  66. } else if (ASIC_IS_AVIVO(rdev)) {
  67. WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
  68. WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
  69. } else {
  70. switch (radeon_crtc->crtc_id) {
  71. case 0:
  72. WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
  73. break;
  74. case 1:
  75. WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
  76. break;
  77. default:
  78. return;
  79. }
  80. WREG32_P(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
  81. }
  82. }
  83. static void radeon_show_cursor(struct drm_crtc *crtc)
  84. {
  85. struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  86. struct radeon_device *rdev = crtc->dev->dev_private;
  87. if (ASIC_IS_DCE4(rdev)) {
  88. WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
  89. WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
  90. EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
  91. } else if (ASIC_IS_AVIVO(rdev)) {
  92. WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
  93. WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
  94. (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
  95. } else {
  96. switch (radeon_crtc->crtc_id) {
  97. case 0:
  98. WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
  99. break;
  100. case 1:
  101. WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
  102. break;
  103. default:
  104. return;
  105. }
  106. WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
  107. (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
  108. ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
  109. }
  110. }
  111. static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
  112. uint64_t gpu_addr)
  113. {
  114. struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  115. struct radeon_device *rdev = crtc->dev->dev_private;
  116. if (ASIC_IS_DCE4(rdev)) {
  117. WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
  118. upper_32_bits(gpu_addr));
  119. WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
  120. gpu_addr & 0xffffffff);
  121. } else if (ASIC_IS_AVIVO(rdev)) {
  122. if (rdev->family >= CHIP_RV770) {
  123. if (radeon_crtc->crtc_id)
  124. WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
  125. else
  126. WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
  127. }
  128. WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
  129. gpu_addr & 0xffffffff);
  130. } else {
  131. radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
  132. /* offset is from DISP(2)_BASE_ADDRESS */
  133. WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, radeon_crtc->legacy_cursor_offset);
  134. }
  135. }
  136. int radeon_crtc_cursor_set(struct drm_crtc *crtc,
  137. struct drm_file *file_priv,
  138. uint32_t handle,
  139. uint32_t width,
  140. uint32_t height)
  141. {
  142. struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  143. struct drm_gem_object *obj;
  144. uint64_t gpu_addr;
  145. int ret;
  146. if (!handle) {
  147. /* turn off cursor */
  148. radeon_hide_cursor(crtc);
  149. obj = NULL;
  150. goto unpin;
  151. }
  152. if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
  153. DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
  154. return -EINVAL;
  155. }
  156. obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
  157. if (!obj) {
  158. DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
  159. return -ENOENT;
  160. }
  161. ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
  162. if (ret)
  163. goto fail;
  164. radeon_crtc->cursor_width = width;
  165. radeon_crtc->cursor_height = height;
  166. radeon_lock_cursor(crtc, true);
  167. /* XXX only 27 bit offset for legacy cursor */
  168. radeon_set_cursor(crtc, obj, gpu_addr);
  169. radeon_show_cursor(crtc);
  170. radeon_lock_cursor(crtc, false);
  171. unpin:
  172. if (radeon_crtc->cursor_bo) {
  173. radeon_gem_object_unpin(radeon_crtc->cursor_bo);
  174. drm_gem_object_unreference_unlocked(radeon_crtc->cursor_bo);
  175. }
  176. radeon_crtc->cursor_bo = obj;
  177. return 0;
  178. fail:
  179. drm_gem_object_unreference_unlocked(obj);
  180. return ret;
  181. }
  182. int radeon_crtc_cursor_move(struct drm_crtc *crtc,
  183. int x, int y)
  184. {
  185. struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
  186. struct radeon_device *rdev = crtc->dev->dev_private;
  187. int xorigin = 0, yorigin = 0;
  188. int w = radeon_crtc->cursor_width;
  189. if (x < 0)
  190. xorigin = -x + 1;
  191. if (y < 0)
  192. yorigin = -y + 1;
  193. if (xorigin >= CURSOR_WIDTH)
  194. xorigin = CURSOR_WIDTH - 1;
  195. if (yorigin >= CURSOR_HEIGHT)
  196. yorigin = CURSOR_HEIGHT - 1;
  197. if (ASIC_IS_AVIVO(rdev)) {
  198. int i = 0;
  199. struct drm_crtc *crtc_p;
  200. /* avivo cursor are offset into the total surface */
  201. x += crtc->x;
  202. y += crtc->y;
  203. DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
  204. /* avivo cursor image can't end on 128 pixel boundary or
  205. * go past the end of the frame if both crtcs are enabled
  206. */
  207. list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
  208. if (crtc_p->enabled)
  209. i++;
  210. }
  211. if (i > 1) {
  212. int cursor_end, frame_end;
  213. cursor_end = x - xorigin + w;
  214. frame_end = crtc->x + crtc->mode.crtc_hdisplay;
  215. if (cursor_end >= frame_end) {
  216. w = w - (cursor_end - frame_end);
  217. if (!(frame_end & 0x7f))
  218. w--;
  219. } else {
  220. if (!(cursor_end & 0x7f))
  221. w--;
  222. }
  223. if (w <= 0)
  224. w = 1;
  225. }
  226. }
  227. radeon_lock_cursor(crtc, true);
  228. if (ASIC_IS_DCE4(rdev)) {
  229. WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
  230. ((xorigin ? 0 : x) << 16) |
  231. (yorigin ? 0 : y));
  232. WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
  233. WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
  234. ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
  235. } else if (ASIC_IS_AVIVO(rdev)) {
  236. WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
  237. ((xorigin ? 0 : x) << 16) |
  238. (yorigin ? 0 : y));
  239. WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
  240. WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
  241. ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
  242. } else {
  243. if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
  244. y *= 2;
  245. WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
  246. (RADEON_CUR_LOCK
  247. | (xorigin << 16)
  248. | yorigin));
  249. WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
  250. (RADEON_CUR_LOCK
  251. | ((xorigin ? 0 : x) << 16)
  252. | (yorigin ? 0 : y)));
  253. /* offset is from DISP(2)_BASE_ADDRESS */
  254. WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
  255. (yorigin * 256)));
  256. }
  257. radeon_lock_cursor(crtc, false);
  258. return 0;
  259. }