armada_plane.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * Copyright (C) 2012 Russell King
  3. * Rewritten from the dovefb driver, and Armada510 manuals.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #include <drm/drmP.h>
  10. #include <drm/drm_atomic.h>
  11. #include <drm/drm_atomic_helper.h>
  12. #include <drm/drm_plane_helper.h>
  13. #include "armada_crtc.h"
  14. #include "armada_drm.h"
  15. #include "armada_fb.h"
  16. #include "armada_gem.h"
  17. #include "armada_hw.h"
  18. #include "armada_plane.h"
  19. #include "armada_trace.h"
  20. static const uint32_t armada_primary_formats[] = {
  21. DRM_FORMAT_UYVY,
  22. DRM_FORMAT_YUYV,
  23. DRM_FORMAT_VYUY,
  24. DRM_FORMAT_YVYU,
  25. DRM_FORMAT_ARGB8888,
  26. DRM_FORMAT_ABGR8888,
  27. DRM_FORMAT_XRGB8888,
  28. DRM_FORMAT_XBGR8888,
  29. DRM_FORMAT_RGB888,
  30. DRM_FORMAT_BGR888,
  31. DRM_FORMAT_ARGB1555,
  32. DRM_FORMAT_ABGR1555,
  33. DRM_FORMAT_RGB565,
  34. DRM_FORMAT_BGR565,
  35. };
  36. void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
  37. u16 pitches[3], bool interlaced)
  38. {
  39. struct drm_framebuffer *fb = state->fb;
  40. const struct drm_format_info *format = fb->format;
  41. unsigned int num_planes = format->num_planes;
  42. unsigned int x = state->src.x1 >> 16;
  43. unsigned int y = state->src.y1 >> 16;
  44. u32 addr = drm_fb_obj(fb)->dev_addr;
  45. int i;
  46. DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
  47. fb->pitches[0], x, y, format->cpp[0] * 8);
  48. if (num_planes > 3)
  49. num_planes = 3;
  50. addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +
  51. x * format->cpp[0];
  52. pitches[0] = fb->pitches[0];
  53. y /= format->vsub;
  54. x /= format->hsub;
  55. for (i = 1; i < num_planes; i++) {
  56. addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +
  57. x * format->cpp[i];
  58. pitches[i] = fb->pitches[i];
  59. }
  60. for (; i < 3; i++) {
  61. addrs[0][i] = 0;
  62. pitches[i] = 0;
  63. }
  64. if (interlaced) {
  65. for (i = 0; i < 3; i++) {
  66. addrs[1][i] = addrs[0][i] + pitches[i];
  67. pitches[i] *= 2;
  68. }
  69. } else {
  70. for (i = 0; i < 3; i++)
  71. addrs[1][i] = addrs[0][i];
  72. }
  73. }
  74. static unsigned armada_drm_crtc_calc_fb(struct drm_plane_state *state,
  75. struct armada_regs *regs, bool interlaced)
  76. {
  77. u16 pitches[3];
  78. u32 addrs[2][3];
  79. unsigned i = 0;
  80. armada_drm_plane_calc(state, addrs, pitches, interlaced);
  81. /* write offset, base, and pitch */
  82. armada_reg_queue_set(regs, i, addrs[0][0], LCD_CFG_GRA_START_ADDR0);
  83. armada_reg_queue_set(regs, i, addrs[1][0], LCD_CFG_GRA_START_ADDR1);
  84. armada_reg_queue_mod(regs, i, pitches[0], 0xffff, LCD_CFG_GRA_PITCH);
  85. return i;
  86. }
  87. int armada_drm_plane_prepare_fb(struct drm_plane *plane,
  88. struct drm_plane_state *state)
  89. {
  90. DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
  91. plane->base.id, plane->name,
  92. state->fb ? state->fb->base.id : 0);
  93. /*
  94. * Take a reference on the new framebuffer - we want to
  95. * hold on to it while the hardware is displaying it.
  96. */
  97. if (state->fb)
  98. drm_framebuffer_get(state->fb);
  99. return 0;
  100. }
  101. void armada_drm_plane_cleanup_fb(struct drm_plane *plane,
  102. struct drm_plane_state *old_state)
  103. {
  104. DRM_DEBUG_KMS("[PLANE:%d:%s] [FB:%d]\n",
  105. plane->base.id, plane->name,
  106. old_state->fb ? old_state->fb->base.id : 0);
  107. if (old_state->fb)
  108. drm_framebuffer_put(old_state->fb);
  109. }
  110. int armada_drm_plane_atomic_check(struct drm_plane *plane,
  111. struct drm_plane_state *state)
  112. {
  113. if (state->fb && !WARN_ON(!state->crtc)) {
  114. struct drm_crtc *crtc = state->crtc;
  115. struct drm_crtc_state *crtc_state;
  116. if (state->state)
  117. crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
  118. else
  119. crtc_state = crtc->state;
  120. return drm_atomic_helper_check_plane_state(state, crtc_state,
  121. 0, INT_MAX,
  122. true, false);
  123. } else {
  124. state->visible = false;
  125. }
  126. return 0;
  127. }
  128. static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
  129. struct drm_plane_state *old_state)
  130. {
  131. struct drm_plane_state *state = plane->state;
  132. struct armada_crtc *dcrtc;
  133. struct armada_regs *regs;
  134. u32 cfg, cfg_mask, val;
  135. unsigned int idx;
  136. DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
  137. if (!state->fb || WARN_ON(!state->crtc))
  138. return;
  139. DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
  140. plane->base.id, plane->name,
  141. state->crtc->base.id, state->crtc->name,
  142. state->fb->base.id,
  143. old_state->visible, state->visible);
  144. dcrtc = drm_to_armada_crtc(state->crtc);
  145. regs = dcrtc->regs + dcrtc->regs_idx;
  146. idx = 0;
  147. if (!old_state->visible && state->visible) {
  148. val = CFG_PDWN64x66;
  149. if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
  150. val |= CFG_PDWN256x24;
  151. armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
  152. }
  153. val = armada_rect_hw_fp(&state->src);
  154. if (armada_rect_hw_fp(&old_state->src) != val)
  155. armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
  156. val = armada_rect_yx(&state->dst);
  157. if (armada_rect_yx(&old_state->dst) != val)
  158. armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
  159. val = armada_rect_hw(&state->dst);
  160. if (armada_rect_hw(&old_state->dst) != val)
  161. armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
  162. if (old_state->src.x1 != state->src.x1 ||
  163. old_state->src.y1 != state->src.y1 ||
  164. old_state->fb != state->fb ||
  165. state->crtc->state->mode_changed) {
  166. idx += armada_drm_crtc_calc_fb(state, regs + idx,
  167. dcrtc->interlaced);
  168. }
  169. if (old_state->fb != state->fb ||
  170. state->crtc->state->mode_changed) {
  171. cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(state->fb)->fmt) |
  172. CFG_GRA_MOD(drm_fb_to_armada_fb(state->fb)->mod);
  173. if (drm_fb_to_armada_fb(state->fb)->fmt > CFG_420)
  174. cfg |= CFG_PALETTE_ENA;
  175. if (state->visible)
  176. cfg |= CFG_GRA_ENA;
  177. if (dcrtc->interlaced)
  178. cfg |= CFG_GRA_FTOGGLE;
  179. cfg_mask = CFG_GRAFORMAT |
  180. CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
  181. CFG_SWAPYU | CFG_YUV2RGB) |
  182. CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
  183. CFG_GRA_ENA;
  184. } else if (old_state->visible != state->visible) {
  185. cfg = state->visible ? CFG_GRA_ENA : 0;
  186. cfg_mask = CFG_GRA_ENA;
  187. } else {
  188. cfg = cfg_mask = 0;
  189. }
  190. if (drm_rect_width(&old_state->src) != drm_rect_width(&state->src) ||
  191. drm_rect_width(&old_state->dst) != drm_rect_width(&state->dst)) {
  192. cfg_mask |= CFG_GRA_HSMOOTH;
  193. if (drm_rect_width(&state->src) >> 16 !=
  194. drm_rect_width(&state->dst))
  195. cfg |= CFG_GRA_HSMOOTH;
  196. }
  197. if (cfg_mask)
  198. armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
  199. LCD_SPU_DMA_CTRL0);
  200. dcrtc->regs_idx += idx;
  201. }
  202. static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
  203. struct drm_plane_state *old_state)
  204. {
  205. struct armada_crtc *dcrtc;
  206. struct armada_regs *regs;
  207. unsigned int idx = 0;
  208. DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
  209. if (!old_state->crtc)
  210. return;
  211. DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
  212. plane->base.id, plane->name,
  213. old_state->crtc->base.id, old_state->crtc->name,
  214. old_state->fb->base.id);
  215. dcrtc = drm_to_armada_crtc(old_state->crtc);
  216. regs = dcrtc->regs + dcrtc->regs_idx;
  217. /* Disable plane and power down most RAMs and FIFOs */
  218. armada_reg_queue_mod(regs, idx, 0, CFG_GRA_ENA, LCD_SPU_DMA_CTRL0);
  219. armada_reg_queue_mod(regs, idx, CFG_PDWN256x32 | CFG_PDWN256x24 |
  220. CFG_PDWN256x8 | CFG_PDWN32x32 | CFG_PDWN64x66,
  221. 0, LCD_SPU_SRAM_PARA1);
  222. dcrtc->regs_idx += idx;
  223. }
  224. static const struct drm_plane_helper_funcs armada_primary_plane_helper_funcs = {
  225. .prepare_fb = armada_drm_plane_prepare_fb,
  226. .cleanup_fb = armada_drm_plane_cleanup_fb,
  227. .atomic_check = armada_drm_plane_atomic_check,
  228. .atomic_update = armada_drm_primary_plane_atomic_update,
  229. .atomic_disable = armada_drm_primary_plane_atomic_disable,
  230. };
  231. static const struct drm_plane_funcs armada_primary_plane_funcs = {
  232. .update_plane = drm_atomic_helper_update_plane,
  233. .disable_plane = drm_atomic_helper_disable_plane,
  234. .destroy = drm_primary_helper_destroy,
  235. .reset = drm_atomic_helper_plane_reset,
  236. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  237. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  238. };
  239. int armada_drm_primary_plane_init(struct drm_device *drm,
  240. struct drm_plane *primary)
  241. {
  242. int ret;
  243. drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);
  244. ret = drm_universal_plane_init(drm, primary, 0,
  245. &armada_primary_plane_funcs,
  246. armada_primary_formats,
  247. ARRAY_SIZE(armada_primary_formats),
  248. NULL,
  249. DRM_PLANE_TYPE_PRIMARY, NULL);
  250. return ret;
  251. }