sun8i_ui_layer.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
  4. *
  5. * Based on sun4i_layer.h, which is:
  6. * Copyright (C) 2015 Free Electrons
  7. * Copyright (C) 2015 NextThing Co
  8. *
  9. * Maxime Ripard <maxime.ripard@free-electrons.com>
  10. */
  11. #include <drm/drm_atomic.h>
  12. #include <drm/drm_atomic_helper.h>
  13. #include <drm/drm_blend.h>
  14. #include <drm/drm_crtc.h>
  15. #include <drm/drm_fb_dma_helper.h>
  16. #include <drm/drm_fourcc.h>
  17. #include <drm/drm_framebuffer.h>
  18. #include <drm/drm_gem_atomic_helper.h>
  19. #include <drm/drm_gem_dma_helper.h>
  20. #include <drm/drm_probe_helper.h>
  21. #include "sun8i_mixer.h"
  22. #include "sun8i_ui_layer.h"
  23. #include "sun8i_ui_scaler.h"
  24. static void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
  25. int overlay, struct drm_plane *plane)
  26. {
  27. u32 mask, val, ch_base;
  28. ch_base = sun8i_channel_base(mixer, channel);
  29. mask = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK |
  30. SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK;
  31. val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA(plane->state->alpha >> 8);
  32. val |= (plane->state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
  33. SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_PIXEL :
  34. SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_COMBINED;
  35. regmap_update_bits(mixer->engine.regs,
  36. SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
  37. mask, val);
  38. }
  39. static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
  40. int overlay, struct drm_plane *plane,
  41. unsigned int zpos)
  42. {
  43. struct drm_plane_state *state = plane->state;
  44. u32 src_w, src_h, dst_w, dst_h;
  45. u32 bld_base, ch_base;
  46. u32 outsize, insize;
  47. u32 hphase, vphase;
  48. DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
  49. channel, overlay);
  50. bld_base = sun8i_blender_base(mixer);
  51. ch_base = sun8i_channel_base(mixer, channel);
  52. src_w = drm_rect_width(&state->src) >> 16;
  53. src_h = drm_rect_height(&state->src) >> 16;
  54. dst_w = drm_rect_width(&state->dst);
  55. dst_h = drm_rect_height(&state->dst);
  56. hphase = state->src.x1 & 0xffff;
  57. vphase = state->src.y1 & 0xffff;
  58. insize = SUN8I_MIXER_SIZE(src_w, src_h);
  59. outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
  60. /* Set height and width */
  61. DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
  62. state->src.x1 >> 16, state->src.y1 >> 16);
  63. DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
  64. regmap_write(mixer->engine.regs,
  65. SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay),
  66. insize);
  67. regmap_write(mixer->engine.regs,
  68. SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base),
  69. insize);
  70. if (insize != outsize || hphase || vphase) {
  71. u32 hscale, vscale;
  72. DRM_DEBUG_DRIVER("HW scaling is enabled\n");
  73. hscale = state->src_w / state->crtc_w;
  74. vscale = state->src_h / state->crtc_h;
  75. sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
  76. dst_h, hscale, vscale, hphase, vphase);
  77. sun8i_ui_scaler_enable(mixer, channel, true);
  78. } else {
  79. DRM_DEBUG_DRIVER("HW scaling is not needed\n");
  80. sun8i_ui_scaler_enable(mixer, channel, false);
  81. }
  82. /* Set base coordinates */
  83. DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
  84. state->dst.x1, state->dst.y1);
  85. DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
  86. regmap_write(mixer->engine.regs,
  87. SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
  88. SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
  89. regmap_write(mixer->engine.regs,
  90. SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
  91. outsize);
  92. return 0;
  93. }
  94. static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
  95. int overlay, struct drm_plane *plane)
  96. {
  97. struct drm_plane_state *state = plane->state;
  98. const struct drm_format_info *fmt;
  99. u32 val, ch_base, hw_fmt;
  100. int ret;
  101. ch_base = sun8i_channel_base(mixer, channel);
  102. fmt = state->fb->format;
  103. ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
  104. if (ret || fmt->is_yuv) {
  105. DRM_DEBUG_DRIVER("Invalid format\n");
  106. return -EINVAL;
  107. }
  108. val = hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
  109. regmap_update_bits(mixer->engine.regs,
  110. SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
  111. SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
  112. return 0;
  113. }
  114. static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
  115. int overlay, struct drm_plane *plane)
  116. {
  117. struct drm_plane_state *state = plane->state;
  118. struct drm_framebuffer *fb = state->fb;
  119. struct drm_gem_dma_object *gem;
  120. dma_addr_t dma_addr;
  121. u32 ch_base;
  122. int bpp;
  123. ch_base = sun8i_channel_base(mixer, channel);
  124. /* Get the physical address of the buffer in memory */
  125. gem = drm_fb_dma_get_gem_obj(fb, 0);
  126. DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->dma_addr);
  127. /* Compute the start of the displayed memory */
  128. bpp = fb->format->cpp[0];
  129. dma_addr = gem->dma_addr + fb->offsets[0];
  130. /* Fixup framebuffer address for src coordinates */
  131. dma_addr += (state->src.x1 >> 16) * bpp;
  132. dma_addr += (state->src.y1 >> 16) * fb->pitches[0];
  133. /* Set the line width */
  134. DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
  135. regmap_write(mixer->engine.regs,
  136. SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay),
  137. fb->pitches[0]);
  138. DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr);
  139. regmap_write(mixer->engine.regs,
  140. SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay),
  141. lower_32_bits(dma_addr));
  142. return 0;
  143. }
  144. static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
  145. struct drm_atomic_state *state)
  146. {
  147. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  148. plane);
  149. struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
  150. struct drm_crtc *crtc = new_plane_state->crtc;
  151. struct drm_crtc_state *crtc_state;
  152. int min_scale, max_scale;
  153. if (!crtc)
  154. return 0;
  155. crtc_state = drm_atomic_get_existing_crtc_state(state,
  156. crtc);
  157. if (WARN_ON(!crtc_state))
  158. return -EINVAL;
  159. min_scale = DRM_PLANE_NO_SCALING;
  160. max_scale = DRM_PLANE_NO_SCALING;
  161. if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
  162. min_scale = SUN8I_UI_SCALER_SCALE_MIN;
  163. max_scale = SUN8I_UI_SCALER_SCALE_MAX;
  164. }
  165. return drm_atomic_helper_check_plane_state(new_plane_state,
  166. crtc_state,
  167. min_scale, max_scale,
  168. true, true);
  169. }
  170. static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
  171. struct drm_atomic_state *state)
  172. {
  173. struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
  174. plane);
  175. struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
  176. unsigned int zpos = new_state->normalized_zpos;
  177. struct sun8i_mixer *mixer = layer->mixer;
  178. if (!new_state->crtc || !new_state->visible)
  179. return;
  180. sun8i_ui_layer_update_coord(mixer, layer->channel,
  181. layer->overlay, plane, zpos);
  182. sun8i_ui_layer_update_alpha(mixer, layer->channel,
  183. layer->overlay, plane);
  184. sun8i_ui_layer_update_formats(mixer, layer->channel,
  185. layer->overlay, plane);
  186. sun8i_ui_layer_update_buffer(mixer, layer->channel,
  187. layer->overlay, plane);
  188. }
  189. static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
  190. .atomic_check = sun8i_ui_layer_atomic_check,
  191. .atomic_update = sun8i_ui_layer_atomic_update,
  192. };
  193. static const struct drm_plane_funcs sun8i_ui_layer_funcs = {
  194. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  195. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  196. .destroy = drm_plane_cleanup,
  197. .disable_plane = drm_atomic_helper_disable_plane,
  198. .reset = drm_atomic_helper_plane_reset,
  199. .update_plane = drm_atomic_helper_update_plane,
  200. };
  201. static const u32 sun8i_ui_layer_formats[] = {
  202. DRM_FORMAT_ABGR1555,
  203. DRM_FORMAT_ABGR4444,
  204. DRM_FORMAT_ABGR8888,
  205. DRM_FORMAT_ARGB1555,
  206. DRM_FORMAT_ARGB4444,
  207. DRM_FORMAT_ARGB8888,
  208. DRM_FORMAT_BGR565,
  209. DRM_FORMAT_BGR888,
  210. DRM_FORMAT_BGRA5551,
  211. DRM_FORMAT_BGRA4444,
  212. DRM_FORMAT_BGRA8888,
  213. DRM_FORMAT_BGRX8888,
  214. DRM_FORMAT_RGB565,
  215. DRM_FORMAT_RGB888,
  216. DRM_FORMAT_RGBA4444,
  217. DRM_FORMAT_RGBA5551,
  218. DRM_FORMAT_RGBA8888,
  219. DRM_FORMAT_RGBX8888,
  220. DRM_FORMAT_XBGR8888,
  221. DRM_FORMAT_XRGB8888,
  222. };
  223. static const uint64_t sun8i_layer_modifiers[] = {
  224. DRM_FORMAT_MOD_LINEAR,
  225. DRM_FORMAT_MOD_INVALID
  226. };
  227. struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
  228. struct sun8i_mixer *mixer,
  229. int index)
  230. {
  231. enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
  232. int channel = mixer->cfg->vi_num + index;
  233. struct sun8i_layer *layer;
  234. unsigned int plane_cnt;
  235. int ret;
  236. layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
  237. if (!layer)
  238. return ERR_PTR(-ENOMEM);
  239. if (index == 0)
  240. type = DRM_PLANE_TYPE_PRIMARY;
  241. /* possible crtcs are set later */
  242. ret = drm_universal_plane_init(drm, &layer->plane, 0,
  243. &sun8i_ui_layer_funcs,
  244. sun8i_ui_layer_formats,
  245. ARRAY_SIZE(sun8i_ui_layer_formats),
  246. sun8i_layer_modifiers, type, NULL);
  247. if (ret) {
  248. dev_err(drm->dev, "Couldn't initialize layer\n");
  249. return ERR_PTR(ret);
  250. }
  251. plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
  252. ret = drm_plane_create_alpha_property(&layer->plane);
  253. if (ret) {
  254. dev_err(drm->dev, "Couldn't add alpha property\n");
  255. return ERR_PTR(ret);
  256. }
  257. ret = drm_plane_create_zpos_property(&layer->plane, channel,
  258. 0, plane_cnt - 1);
  259. if (ret) {
  260. dev_err(drm->dev, "Couldn't add zpos property\n");
  261. return ERR_PTR(ret);
  262. }
  263. drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
  264. layer->mixer = mixer;
  265. layer->type = SUN8I_LAYER_TYPE_UI;
  266. layer->channel = channel;
  267. layer->overlay = 0;
  268. return layer;
  269. }