ipuv3-plane.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /*
  2. * i.MX IPUv3 DP Overlay Planes
  3. *
  4. * Copyright (C) 2013 Philipp Zabel, Pengutronix
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <drm/drmP.h>
  16. #include <drm/drm_fb_cma_helper.h>
  17. #include <drm/drm_gem_cma_helper.h>
  18. #include "video/imx-ipu-v3.h"
  19. #include "ipuv3-plane.h"
  20. #define to_ipu_plane(x) container_of(x, struct ipu_plane, base)
  21. static const uint32_t ipu_plane_formats[] = {
  22. DRM_FORMAT_ARGB1555,
  23. DRM_FORMAT_XRGB1555,
  24. DRM_FORMAT_ABGR1555,
  25. DRM_FORMAT_XBGR1555,
  26. DRM_FORMAT_RGBA5551,
  27. DRM_FORMAT_BGRA5551,
  28. DRM_FORMAT_ARGB4444,
  29. DRM_FORMAT_ARGB8888,
  30. DRM_FORMAT_XRGB8888,
  31. DRM_FORMAT_ABGR8888,
  32. DRM_FORMAT_XBGR8888,
  33. DRM_FORMAT_RGBA8888,
  34. DRM_FORMAT_RGBX8888,
  35. DRM_FORMAT_BGRA8888,
  36. DRM_FORMAT_BGRA8888,
  37. DRM_FORMAT_YUYV,
  38. DRM_FORMAT_YVYU,
  39. DRM_FORMAT_YUV420,
  40. DRM_FORMAT_YVU420,
  41. DRM_FORMAT_RGB565,
  42. };
  43. int ipu_plane_irq(struct ipu_plane *ipu_plane)
  44. {
  45. return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
  46. IPU_IRQ_EOF);
  47. }
  48. static int calc_vref(struct drm_display_mode *mode)
  49. {
  50. unsigned long htotal, vtotal;
  51. htotal = mode->htotal;
  52. vtotal = mode->vtotal;
  53. if (!htotal || !vtotal)
  54. return 60;
  55. return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
  56. }
  57. static inline int calc_bandwidth(int width, int height, unsigned int vref)
  58. {
  59. return width * height * vref;
  60. }
  61. int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
  62. int x, int y)
  63. {
  64. struct drm_gem_cma_object *cma_obj;
  65. unsigned long eba;
  66. int active;
  67. cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
  68. if (!cma_obj) {
  69. DRM_DEBUG_KMS("entry is null.\n");
  70. return -EFAULT;
  71. }
  72. dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
  73. &cma_obj->paddr, x, y);
  74. eba = cma_obj->paddr + fb->offsets[0] +
  75. fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
  76. if (ipu_plane->enabled) {
  77. active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
  78. ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
  79. ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
  80. } else {
  81. ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
  82. ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
  83. }
  84. /* cache offsets for subsequent pageflips */
  85. ipu_plane->x = x;
  86. ipu_plane->y = y;
  87. return 0;
  88. }
  89. int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
  90. struct drm_display_mode *mode,
  91. struct drm_framebuffer *fb, int crtc_x, int crtc_y,
  92. unsigned int crtc_w, unsigned int crtc_h,
  93. uint32_t src_x, uint32_t src_y,
  94. uint32_t src_w, uint32_t src_h, bool interlaced)
  95. {
  96. struct device *dev = ipu_plane->base.dev->dev;
  97. int ret;
  98. /* no scaling */
  99. if (src_w != crtc_w || src_h != crtc_h)
  100. return -EINVAL;
  101. /* clip to crtc bounds */
  102. if (crtc_x < 0) {
  103. if (-crtc_x > crtc_w)
  104. return -EINVAL;
  105. src_x += -crtc_x;
  106. src_w -= -crtc_x;
  107. crtc_w -= -crtc_x;
  108. crtc_x = 0;
  109. }
  110. if (crtc_y < 0) {
  111. if (-crtc_y > crtc_h)
  112. return -EINVAL;
  113. src_y += -crtc_y;
  114. src_h -= -crtc_y;
  115. crtc_h -= -crtc_y;
  116. crtc_y = 0;
  117. }
  118. if (crtc_x + crtc_w > mode->hdisplay) {
  119. if (crtc_x > mode->hdisplay)
  120. return -EINVAL;
  121. crtc_w = mode->hdisplay - crtc_x;
  122. src_w = crtc_w;
  123. }
  124. if (crtc_y + crtc_h > mode->vdisplay) {
  125. if (crtc_y > mode->vdisplay)
  126. return -EINVAL;
  127. crtc_h = mode->vdisplay - crtc_y;
  128. src_h = crtc_h;
  129. }
  130. /* full plane minimum width is 13 pixels */
  131. if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
  132. return -EINVAL;
  133. if (crtc_h < 2)
  134. return -EINVAL;
  135. /*
  136. * since we cannot touch active IDMAC channels, we do not support
  137. * resizing the enabled plane or changing its format
  138. */
  139. if (ipu_plane->enabled) {
  140. if (src_w != ipu_plane->w || src_h != ipu_plane->h ||
  141. fb->pixel_format != ipu_plane->base.fb->pixel_format)
  142. return -EINVAL;
  143. return ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
  144. }
  145. switch (ipu_plane->dp_flow) {
  146. case IPU_DP_FLOW_SYNC_BG:
  147. ret = ipu_dp_setup_channel(ipu_plane->dp,
  148. IPUV3_COLORSPACE_RGB,
  149. IPUV3_COLORSPACE_RGB);
  150. if (ret) {
  151. dev_err(dev,
  152. "initializing display processor failed with %d\n",
  153. ret);
  154. return ret;
  155. }
  156. ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
  157. break;
  158. case IPU_DP_FLOW_SYNC_FG:
  159. ipu_dp_setup_channel(ipu_plane->dp,
  160. ipu_drm_fourcc_to_colorspace(fb->pixel_format),
  161. IPUV3_COLORSPACE_UNKNOWN);
  162. ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
  163. /* Enable local alpha on partial plane */
  164. switch (fb->pixel_format) {
  165. case DRM_FORMAT_ARGB1555:
  166. case DRM_FORMAT_ABGR1555:
  167. case DRM_FORMAT_RGBA5551:
  168. case DRM_FORMAT_BGRA5551:
  169. case DRM_FORMAT_ARGB4444:
  170. case DRM_FORMAT_ARGB8888:
  171. case DRM_FORMAT_ABGR8888:
  172. case DRM_FORMAT_RGBA8888:
  173. case DRM_FORMAT_BGRA8888:
  174. ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
  175. break;
  176. default:
  177. break;
  178. }
  179. }
  180. ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
  181. if (ret) {
  182. dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
  183. return ret;
  184. }
  185. ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
  186. calc_bandwidth(crtc_w, crtc_h,
  187. calc_vref(mode)), 64);
  188. if (ret) {
  189. dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
  190. return ret;
  191. }
  192. ipu_cpmem_zero(ipu_plane->ipu_ch);
  193. ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
  194. ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
  195. if (ret < 0) {
  196. dev_err(dev, "unsupported pixel format 0x%08x\n",
  197. fb->pixel_format);
  198. return ret;
  199. }
  200. ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
  201. ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
  202. ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
  203. ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
  204. if (ret < 0)
  205. return ret;
  206. if (interlaced)
  207. ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
  208. ipu_plane->w = src_w;
  209. ipu_plane->h = src_h;
  210. return 0;
  211. }
  212. void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
  213. {
  214. if (!IS_ERR_OR_NULL(ipu_plane->dp))
  215. ipu_dp_put(ipu_plane->dp);
  216. if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
  217. ipu_dmfc_put(ipu_plane->dmfc);
  218. if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
  219. ipu_idmac_put(ipu_plane->ipu_ch);
  220. }
  221. int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
  222. {
  223. int ret;
  224. ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
  225. if (IS_ERR(ipu_plane->ipu_ch)) {
  226. ret = PTR_ERR(ipu_plane->ipu_ch);
  227. DRM_ERROR("failed to get idmac channel: %d\n", ret);
  228. return ret;
  229. }
  230. ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
  231. if (IS_ERR(ipu_plane->dmfc)) {
  232. ret = PTR_ERR(ipu_plane->dmfc);
  233. DRM_ERROR("failed to get dmfc: ret %d\n", ret);
  234. goto err_out;
  235. }
  236. if (ipu_plane->dp_flow >= 0) {
  237. ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
  238. if (IS_ERR(ipu_plane->dp)) {
  239. ret = PTR_ERR(ipu_plane->dp);
  240. DRM_ERROR("failed to get dp flow: %d\n", ret);
  241. goto err_out;
  242. }
  243. }
  244. return 0;
  245. err_out:
  246. ipu_plane_put_resources(ipu_plane);
  247. return ret;
  248. }
  249. void ipu_plane_enable(struct ipu_plane *ipu_plane)
  250. {
  251. if (ipu_plane->dp)
  252. ipu_dp_enable(ipu_plane->ipu);
  253. ipu_dmfc_enable_channel(ipu_plane->dmfc);
  254. ipu_idmac_enable_channel(ipu_plane->ipu_ch);
  255. if (ipu_plane->dp)
  256. ipu_dp_enable_channel(ipu_plane->dp);
  257. ipu_plane->enabled = true;
  258. }
  259. void ipu_plane_disable(struct ipu_plane *ipu_plane)
  260. {
  261. ipu_plane->enabled = false;
  262. ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
  263. if (ipu_plane->dp)
  264. ipu_dp_disable_channel(ipu_plane->dp);
  265. ipu_idmac_disable_channel(ipu_plane->ipu_ch);
  266. ipu_dmfc_disable_channel(ipu_plane->dmfc);
  267. if (ipu_plane->dp)
  268. ipu_dp_disable(ipu_plane->ipu);
  269. }
  270. /*
  271. * drm_plane API
  272. */
  273. static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
  274. struct drm_framebuffer *fb, int crtc_x, int crtc_y,
  275. unsigned int crtc_w, unsigned int crtc_h,
  276. uint32_t src_x, uint32_t src_y,
  277. uint32_t src_w, uint32_t src_h)
  278. {
  279. struct ipu_plane *ipu_plane = to_ipu_plane(plane);
  280. int ret = 0;
  281. DRM_DEBUG_KMS("plane - %p\n", plane);
  282. if (!ipu_plane->enabled)
  283. ret = ipu_plane_get_resources(ipu_plane);
  284. if (ret < 0)
  285. return ret;
  286. ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
  287. crtc_x, crtc_y, crtc_w, crtc_h,
  288. src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
  289. false);
  290. if (ret < 0) {
  291. ipu_plane_put_resources(ipu_plane);
  292. return ret;
  293. }
  294. if (crtc != plane->crtc)
  295. dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n",
  296. plane->crtc, crtc);
  297. plane->crtc = crtc;
  298. if (!ipu_plane->enabled)
  299. ipu_plane_enable(ipu_plane);
  300. return 0;
  301. }
  302. static int ipu_disable_plane(struct drm_plane *plane)
  303. {
  304. struct ipu_plane *ipu_plane = to_ipu_plane(plane);
  305. DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
  306. if (ipu_plane->enabled)
  307. ipu_plane_disable(ipu_plane);
  308. ipu_plane_put_resources(ipu_plane);
  309. return 0;
  310. }
  311. static void ipu_plane_destroy(struct drm_plane *plane)
  312. {
  313. struct ipu_plane *ipu_plane = to_ipu_plane(plane);
  314. DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
  315. ipu_disable_plane(plane);
  316. drm_plane_cleanup(plane);
  317. kfree(ipu_plane);
  318. }
  319. static struct drm_plane_funcs ipu_plane_funcs = {
  320. .update_plane = ipu_update_plane,
  321. .disable_plane = ipu_disable_plane,
  322. .destroy = ipu_plane_destroy,
  323. };
  324. struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
  325. int dma, int dp, unsigned int possible_crtcs,
  326. enum drm_plane_type type)
  327. {
  328. struct ipu_plane *ipu_plane;
  329. int ret;
  330. DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
  331. dma, dp, possible_crtcs);
  332. ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
  333. if (!ipu_plane) {
  334. DRM_ERROR("failed to allocate plane\n");
  335. return ERR_PTR(-ENOMEM);
  336. }
  337. ipu_plane->ipu = ipu;
  338. ipu_plane->dma = dma;
  339. ipu_plane->dp_flow = dp;
  340. ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
  341. &ipu_plane_funcs, ipu_plane_formats,
  342. ARRAY_SIZE(ipu_plane_formats), type,
  343. NULL);
  344. if (ret) {
  345. DRM_ERROR("failed to initialize plane\n");
  346. kfree(ipu_plane);
  347. return ERR_PTR(ret);
  348. }
  349. return ipu_plane;
  350. }