ipuv3-plane.c 10 KB

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