armada_plane.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2012 Russell King
  4. * Rewritten from the dovefb driver, and Armada510 manuals.
  5. */
  6. #include <drm/drm_atomic.h>
  7. #include <drm/drm_atomic_helper.h>
  8. #include <drm/drm_fourcc.h>
  9. #include <drm/drm_plane_helper.h>
  10. #include "armada_crtc.h"
  11. #include "armada_drm.h"
  12. #include "armada_fb.h"
  13. #include "armada_gem.h"
  14. #include "armada_hw.h"
  15. #include "armada_plane.h"
  16. #include "armada_trace.h"
  17. static const uint32_t armada_primary_formats[] = {
  18. DRM_FORMAT_UYVY,
  19. DRM_FORMAT_YUYV,
  20. DRM_FORMAT_VYUY,
  21. DRM_FORMAT_YVYU,
  22. DRM_FORMAT_ARGB8888,
  23. DRM_FORMAT_ABGR8888,
  24. DRM_FORMAT_XRGB8888,
  25. DRM_FORMAT_XBGR8888,
  26. DRM_FORMAT_RGB888,
  27. DRM_FORMAT_BGR888,
  28. DRM_FORMAT_ARGB1555,
  29. DRM_FORMAT_ABGR1555,
  30. DRM_FORMAT_RGB565,
  31. DRM_FORMAT_BGR565,
  32. };
  33. void armada_drm_plane_calc(struct drm_plane_state *state, u32 addrs[2][3],
  34. u16 pitches[3], bool interlaced)
  35. {
  36. struct drm_framebuffer *fb = state->fb;
  37. const struct drm_format_info *format = fb->format;
  38. unsigned int num_planes = format->num_planes;
  39. unsigned int x = state->src.x1 >> 16;
  40. unsigned int y = state->src.y1 >> 16;
  41. u32 addr = drm_fb_obj(fb)->dev_addr;
  42. int i;
  43. DRM_DEBUG_KMS("pitch %u x %d y %d bpp %d\n",
  44. fb->pitches[0], x, y, format->cpp[0] * 8);
  45. if (num_planes > 3)
  46. num_planes = 3;
  47. addrs[0][0] = addr + fb->offsets[0] + y * fb->pitches[0] +
  48. x * format->cpp[0];
  49. pitches[0] = fb->pitches[0];
  50. y /= format->vsub;
  51. x /= format->hsub;
  52. for (i = 1; i < num_planes; i++) {
  53. addrs[0][i] = addr + fb->offsets[i] + y * fb->pitches[i] +
  54. x * format->cpp[i];
  55. pitches[i] = fb->pitches[i];
  56. }
  57. for (; i < 3; i++) {
  58. addrs[0][i] = 0;
  59. pitches[i] = 0;
  60. }
  61. if (interlaced) {
  62. for (i = 0; i < 3; i++) {
  63. addrs[1][i] = addrs[0][i] + pitches[i];
  64. pitches[i] *= 2;
  65. }
  66. } else {
  67. for (i = 0; i < 3; i++)
  68. addrs[1][i] = addrs[0][i];
  69. }
  70. }
  71. int armada_drm_plane_atomic_check(struct drm_plane *plane,
  72. struct drm_atomic_state *state)
  73. {
  74. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  75. plane);
  76. struct armada_plane_state *st = to_armada_plane_state(new_plane_state);
  77. struct drm_crtc *crtc = new_plane_state->crtc;
  78. struct drm_crtc_state *crtc_state;
  79. bool interlace;
  80. int ret;
  81. if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc)) {
  82. new_plane_state->visible = false;
  83. return 0;
  84. }
  85. if (state)
  86. crtc_state = drm_atomic_get_existing_crtc_state(state,
  87. crtc);
  88. else
  89. crtc_state = crtc->state;
  90. ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
  91. 0,
  92. INT_MAX, true, false);
  93. if (ret)
  94. return ret;
  95. interlace = crtc_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE;
  96. if (interlace) {
  97. if ((new_plane_state->dst.y1 | new_plane_state->dst.y2) & 1)
  98. return -EINVAL;
  99. st->src_hw = drm_rect_height(&new_plane_state->src) >> 17;
  100. st->dst_yx = new_plane_state->dst.y1 >> 1;
  101. st->dst_hw = drm_rect_height(&new_plane_state->dst) >> 1;
  102. } else {
  103. st->src_hw = drm_rect_height(&new_plane_state->src) >> 16;
  104. st->dst_yx = new_plane_state->dst.y1;
  105. st->dst_hw = drm_rect_height(&new_plane_state->dst);
  106. }
  107. st->src_hw <<= 16;
  108. st->src_hw |= drm_rect_width(&new_plane_state->src) >> 16;
  109. st->dst_yx <<= 16;
  110. st->dst_yx |= new_plane_state->dst.x1 & 0x0000ffff;
  111. st->dst_hw <<= 16;
  112. st->dst_hw |= drm_rect_width(&new_plane_state->dst) & 0x0000ffff;
  113. armada_drm_plane_calc(new_plane_state, st->addrs, st->pitches,
  114. interlace);
  115. st->interlace = interlace;
  116. return 0;
  117. }
  118. static void armada_drm_primary_plane_atomic_update(struct drm_plane *plane,
  119. struct drm_atomic_state *state)
  120. {
  121. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  122. plane);
  123. struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
  124. plane);
  125. struct armada_crtc *dcrtc;
  126. struct armada_regs *regs;
  127. u32 cfg, cfg_mask, val;
  128. unsigned int idx;
  129. DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
  130. if (!new_state->fb || WARN_ON(!new_state->crtc))
  131. return;
  132. DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
  133. plane->base.id, plane->name,
  134. new_state->crtc->base.id, new_state->crtc->name,
  135. new_state->fb->base.id,
  136. old_state->visible, new_state->visible);
  137. dcrtc = drm_to_armada_crtc(new_state->crtc);
  138. regs = dcrtc->regs + dcrtc->regs_idx;
  139. idx = 0;
  140. if (!old_state->visible && new_state->visible) {
  141. val = CFG_PDWN64x66;
  142. if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
  143. val |= CFG_PDWN256x24;
  144. armada_reg_queue_mod(regs, idx, 0, val, LCD_SPU_SRAM_PARA1);
  145. }
  146. val = armada_src_hw(new_state);
  147. if (armada_src_hw(old_state) != val)
  148. armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_HPXL_VLN);
  149. val = armada_dst_yx(new_state);
  150. if (armada_dst_yx(old_state) != val)
  151. armada_reg_queue_set(regs, idx, val, LCD_SPU_GRA_OVSA_HPXL_VLN);
  152. val = armada_dst_hw(new_state);
  153. if (armada_dst_hw(old_state) != val)
  154. armada_reg_queue_set(regs, idx, val, LCD_SPU_GZM_HPXL_VLN);
  155. if (old_state->src.x1 != new_state->src.x1 ||
  156. old_state->src.y1 != new_state->src.y1 ||
  157. old_state->fb != new_state->fb ||
  158. new_state->crtc->state->mode_changed) {
  159. armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),
  160. LCD_CFG_GRA_START_ADDR0);
  161. armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),
  162. LCD_CFG_GRA_START_ADDR1);
  163. armada_reg_queue_mod(regs, idx, armada_pitch(new_state, 0),
  164. 0xffff,
  165. LCD_CFG_GRA_PITCH);
  166. }
  167. if (old_state->fb != new_state->fb ||
  168. new_state->crtc->state->mode_changed) {
  169. cfg = CFG_GRA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |
  170. CFG_GRA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod);
  171. if (drm_fb_to_armada_fb(new_state->fb)->fmt > CFG_420)
  172. cfg |= CFG_PALETTE_ENA;
  173. if (new_state->visible)
  174. cfg |= CFG_GRA_ENA;
  175. if (to_armada_plane_state(new_state)->interlace)
  176. cfg |= CFG_GRA_FTOGGLE;
  177. cfg_mask = CFG_GRAFORMAT |
  178. CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
  179. CFG_SWAPYU | CFG_YUV2RGB) |
  180. CFG_PALETTE_ENA | CFG_GRA_FTOGGLE |
  181. CFG_GRA_ENA;
  182. } else if (old_state->visible != new_state->visible) {
  183. cfg = new_state->visible ? CFG_GRA_ENA : 0;
  184. cfg_mask = CFG_GRA_ENA;
  185. } else {
  186. cfg = cfg_mask = 0;
  187. }
  188. if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||
  189. drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {
  190. cfg_mask |= CFG_GRA_HSMOOTH;
  191. if (drm_rect_width(&new_state->src) >> 16 !=
  192. drm_rect_width(&new_state->dst))
  193. cfg |= CFG_GRA_HSMOOTH;
  194. }
  195. if (cfg_mask)
  196. armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
  197. LCD_SPU_DMA_CTRL0);
  198. dcrtc->regs_idx += idx;
  199. }
  200. static void armada_drm_primary_plane_atomic_disable(struct drm_plane *plane,
  201. struct drm_atomic_state *state)
  202. {
  203. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  204. plane);
  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_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. .atomic_check = armada_drm_plane_atomic_check,
  226. .atomic_update = armada_drm_primary_plane_atomic_update,
  227. .atomic_disable = armada_drm_primary_plane_atomic_disable,
  228. };
  229. void armada_plane_reset(struct drm_plane *plane)
  230. {
  231. struct armada_plane_state *st;
  232. if (plane->state)
  233. __drm_atomic_helper_plane_destroy_state(plane->state);
  234. kfree(plane->state);
  235. st = kzalloc(sizeof(*st), GFP_KERNEL);
  236. if (st)
  237. __drm_atomic_helper_plane_reset(plane, &st->base);
  238. }
  239. struct drm_plane_state *armada_plane_duplicate_state(struct drm_plane *plane)
  240. {
  241. struct armada_plane_state *st;
  242. if (WARN_ON(!plane->state))
  243. return NULL;
  244. st = kmemdup(plane->state, sizeof(*st), GFP_KERNEL);
  245. if (st)
  246. __drm_atomic_helper_plane_duplicate_state(plane, &st->base);
  247. return &st->base;
  248. }
  249. static const struct drm_plane_funcs armada_primary_plane_funcs = {
  250. .update_plane = drm_atomic_helper_update_plane,
  251. .disable_plane = drm_atomic_helper_disable_plane,
  252. .destroy = drm_plane_helper_destroy,
  253. .reset = armada_plane_reset,
  254. .atomic_duplicate_state = armada_plane_duplicate_state,
  255. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  256. };
  257. int armada_drm_primary_plane_init(struct drm_device *drm,
  258. struct drm_plane *primary)
  259. {
  260. int ret;
  261. drm_plane_helper_add(primary, &armada_primary_plane_helper_funcs);
  262. ret = drm_universal_plane_init(drm, primary, 0,
  263. &armada_primary_plane_funcs,
  264. armada_primary_formats,
  265. ARRAY_SIZE(armada_primary_formats),
  266. NULL,
  267. DRM_PLANE_TYPE_PRIMARY, NULL);
  268. return ret;
  269. }