sun8i_ui_layer.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
  3. *
  4. * Based on sun4i_layer.h, which is:
  5. * Copyright (C) 2015 Free Electrons
  6. * Copyright (C) 2015 NextThing Co
  7. *
  8. * Maxime Ripard <maxime.ripard@free-electrons.com>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of
  13. * the License, or (at your option) any later version.
  14. */
  15. #include <drm/drm_atomic.h>
  16. #include <drm/drm_atomic_helper.h>
  17. #include <drm/drm_crtc.h>
  18. #include <drm/drm_crtc_helper.h>
  19. #include <drm/drm_fb_cma_helper.h>
  20. #include <drm/drm_gem_cma_helper.h>
  21. #include <drm/drm_plane_helper.h>
  22. #include <drm/drmP.h>
  23. #include "sun8i_ui_layer.h"
  24. #include "sun8i_mixer.h"
  25. #include "sun8i_ui_scaler.h"
  26. static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
  27. int overlay, bool enable)
  28. {
  29. u32 val;
  30. DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
  31. enable ? "En" : "Dis", channel, overlay);
  32. if (enable)
  33. val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
  34. else
  35. val = 0;
  36. regmap_update_bits(mixer->engine.regs,
  37. SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
  38. SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
  39. if (enable)
  40. val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel);
  41. else
  42. val = 0;
  43. regmap_update_bits(mixer->engine.regs,
  44. SUN8I_MIXER_BLEND_PIPE_CTL,
  45. SUN8I_MIXER_BLEND_PIPE_CTL_EN(channel), val);
  46. }
  47. static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
  48. int overlay, struct drm_plane *plane)
  49. {
  50. struct drm_plane_state *state = plane->state;
  51. u32 src_w, src_h, dst_w, dst_h;
  52. u32 outsize, insize;
  53. u32 hphase, vphase;
  54. DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
  55. channel, overlay);
  56. src_w = drm_rect_width(&state->src) >> 16;
  57. src_h = drm_rect_height(&state->src) >> 16;
  58. dst_w = drm_rect_width(&state->dst);
  59. dst_h = drm_rect_height(&state->dst);
  60. hphase = state->src.x1 & 0xffff;
  61. vphase = state->src.y1 & 0xffff;
  62. insize = SUN8I_MIXER_SIZE(src_w, src_h);
  63. outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
  64. if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
  65. bool interlaced = false;
  66. u32 val;
  67. DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
  68. dst_w, dst_h);
  69. regmap_write(mixer->engine.regs,
  70. SUN8I_MIXER_GLOBAL_SIZE,
  71. outsize);
  72. regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
  73. outsize);
  74. if (state->crtc)
  75. interlaced = state->crtc->state->adjusted_mode.flags
  76. & DRM_MODE_FLAG_INTERLACE;
  77. if (interlaced)
  78. val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
  79. else
  80. val = 0;
  81. regmap_update_bits(mixer->engine.regs,
  82. SUN8I_MIXER_BLEND_OUTCTL,
  83. SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
  84. val);
  85. DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
  86. interlaced ? "on" : "off");
  87. }
  88. /* Set height and width */
  89. DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
  90. state->src.x1 >> 16, state->src.y1 >> 16);
  91. DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
  92. regmap_write(mixer->engine.regs,
  93. SUN8I_MIXER_CHAN_UI_LAYER_SIZE(channel, overlay),
  94. insize);
  95. regmap_write(mixer->engine.regs,
  96. SUN8I_MIXER_CHAN_UI_OVL_SIZE(channel),
  97. insize);
  98. if (insize != outsize || hphase || vphase) {
  99. u32 hscale, vscale;
  100. DRM_DEBUG_DRIVER("HW scaling is enabled\n");
  101. hscale = state->src_w / state->crtc_w;
  102. vscale = state->src_h / state->crtc_h;
  103. sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
  104. dst_h, hscale, vscale, hphase, vphase);
  105. sun8i_ui_scaler_enable(mixer, channel, true);
  106. } else {
  107. DRM_DEBUG_DRIVER("HW scaling is not needed\n");
  108. sun8i_ui_scaler_enable(mixer, channel, false);
  109. }
  110. /* Set base coordinates */
  111. DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
  112. state->dst.x1, state->dst.y1);
  113. DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
  114. regmap_write(mixer->engine.regs,
  115. SUN8I_MIXER_BLEND_ATTR_COORD(channel),
  116. SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
  117. regmap_write(mixer->engine.regs,
  118. SUN8I_MIXER_BLEND_ATTR_INSIZE(channel),
  119. outsize);
  120. return 0;
  121. }
  122. static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
  123. int overlay, struct drm_plane *plane)
  124. {
  125. struct drm_plane_state *state = plane->state;
  126. const struct de2_fmt_info *fmt_info;
  127. u32 val;
  128. fmt_info = sun8i_mixer_format_info(state->fb->format->format);
  129. if (!fmt_info || !fmt_info->rgb) {
  130. DRM_DEBUG_DRIVER("Invalid format\n");
  131. return -EINVAL;
  132. }
  133. val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
  134. regmap_update_bits(mixer->engine.regs,
  135. SUN8I_MIXER_CHAN_UI_LAYER_ATTR(channel, overlay),
  136. SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
  137. return 0;
  138. }
  139. static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
  140. int overlay, struct drm_plane *plane)
  141. {
  142. struct drm_plane_state *state = plane->state;
  143. struct drm_framebuffer *fb = state->fb;
  144. struct drm_gem_cma_object *gem;
  145. dma_addr_t paddr;
  146. int bpp;
  147. /* Get the physical address of the buffer in memory */
  148. gem = drm_fb_cma_get_gem_obj(fb, 0);
  149. DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
  150. /* Compute the start of the displayed memory */
  151. bpp = fb->format->cpp[0];
  152. paddr = gem->paddr + fb->offsets[0];
  153. /* Fixup framebuffer address for src coordinates */
  154. paddr += (state->src.x1 >> 16) * bpp;
  155. paddr += (state->src.y1 >> 16) * fb->pitches[0];
  156. /* Set the line width */
  157. DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
  158. regmap_write(mixer->engine.regs,
  159. SUN8I_MIXER_CHAN_UI_LAYER_PITCH(channel, overlay),
  160. fb->pitches[0]);
  161. DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
  162. regmap_write(mixer->engine.regs,
  163. SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(channel, overlay),
  164. lower_32_bits(paddr));
  165. return 0;
  166. }
  167. static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
  168. struct drm_plane_state *state)
  169. {
  170. struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
  171. struct drm_crtc *crtc = state->crtc;
  172. struct drm_crtc_state *crtc_state;
  173. int min_scale, max_scale;
  174. if (!crtc)
  175. return 0;
  176. crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
  177. if (WARN_ON(!crtc_state))
  178. return -EINVAL;
  179. min_scale = DRM_PLANE_HELPER_NO_SCALING;
  180. max_scale = DRM_PLANE_HELPER_NO_SCALING;
  181. if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
  182. min_scale = SUN8I_UI_SCALER_SCALE_MIN;
  183. max_scale = SUN8I_UI_SCALER_SCALE_MAX;
  184. }
  185. return drm_atomic_helper_check_plane_state(state, crtc_state,
  186. min_scale, max_scale,
  187. true, true);
  188. }
  189. static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane,
  190. struct drm_plane_state *old_state)
  191. {
  192. struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
  193. struct sun8i_mixer *mixer = layer->mixer;
  194. sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, false);
  195. }
  196. static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
  197. struct drm_plane_state *old_state)
  198. {
  199. struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
  200. struct sun8i_mixer *mixer = layer->mixer;
  201. if (!plane->state->visible) {
  202. sun8i_ui_layer_enable(mixer, layer->channel,
  203. layer->overlay, false);
  204. return;
  205. }
  206. sun8i_ui_layer_update_coord(mixer, layer->channel,
  207. layer->overlay, plane);
  208. sun8i_ui_layer_update_formats(mixer, layer->channel,
  209. layer->overlay, plane);
  210. sun8i_ui_layer_update_buffer(mixer, layer->channel,
  211. layer->overlay, plane);
  212. sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay, true);
  213. }
  214. static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
  215. .atomic_check = sun8i_ui_layer_atomic_check,
  216. .atomic_disable = sun8i_ui_layer_atomic_disable,
  217. .atomic_update = sun8i_ui_layer_atomic_update,
  218. };
  219. static const struct drm_plane_funcs sun8i_ui_layer_funcs = {
  220. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  221. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  222. .destroy = drm_plane_cleanup,
  223. .disable_plane = drm_atomic_helper_disable_plane,
  224. .reset = drm_atomic_helper_plane_reset,
  225. .update_plane = drm_atomic_helper_update_plane,
  226. };
  227. static const u32 sun8i_ui_layer_formats[] = {
  228. DRM_FORMAT_ABGR1555,
  229. DRM_FORMAT_ABGR4444,
  230. DRM_FORMAT_ABGR8888,
  231. DRM_FORMAT_ARGB1555,
  232. DRM_FORMAT_ARGB4444,
  233. DRM_FORMAT_ARGB8888,
  234. DRM_FORMAT_BGR565,
  235. DRM_FORMAT_BGR888,
  236. DRM_FORMAT_BGRA5551,
  237. DRM_FORMAT_BGRA4444,
  238. DRM_FORMAT_BGRA8888,
  239. DRM_FORMAT_BGRX8888,
  240. DRM_FORMAT_RGB565,
  241. DRM_FORMAT_RGB888,
  242. DRM_FORMAT_RGBA4444,
  243. DRM_FORMAT_RGBA5551,
  244. DRM_FORMAT_RGBA8888,
  245. DRM_FORMAT_RGBX8888,
  246. DRM_FORMAT_XBGR8888,
  247. DRM_FORMAT_XRGB8888,
  248. };
  249. struct sun8i_ui_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
  250. struct sun8i_mixer *mixer,
  251. int index)
  252. {
  253. enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
  254. int channel = mixer->cfg->vi_num + index;
  255. struct sun8i_ui_layer *layer;
  256. int ret;
  257. layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
  258. if (!layer)
  259. return ERR_PTR(-ENOMEM);
  260. if (index == 0)
  261. type = DRM_PLANE_TYPE_PRIMARY;
  262. /* possible crtcs are set later */
  263. ret = drm_universal_plane_init(drm, &layer->plane, 0,
  264. &sun8i_ui_layer_funcs,
  265. sun8i_ui_layer_formats,
  266. ARRAY_SIZE(sun8i_ui_layer_formats),
  267. NULL, type, NULL);
  268. if (ret) {
  269. dev_err(drm->dev, "Couldn't initialize layer\n");
  270. return ERR_PTR(ret);
  271. }
  272. /* fixed zpos for now */
  273. ret = drm_plane_create_zpos_immutable_property(&layer->plane, channel);
  274. if (ret) {
  275. dev_err(drm->dev, "Couldn't add zpos property\n");
  276. return ERR_PTR(ret);
  277. }
  278. drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
  279. layer->mixer = mixer;
  280. layer->channel = channel;
  281. layer->overlay = 0;
  282. return layer;
  283. }