ipuv3-plane.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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_UYVY,
  38. DRM_FORMAT_VYUY,
  39. DRM_FORMAT_YUYV,
  40. DRM_FORMAT_YVYU,
  41. DRM_FORMAT_YUV420,
  42. DRM_FORMAT_YVU420,
  43. DRM_FORMAT_RGB565,
  44. };
  45. int ipu_plane_irq(struct ipu_plane *ipu_plane)
  46. {
  47. return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
  48. IPU_IRQ_EOF);
  49. }
  50. static int calc_vref(struct drm_display_mode *mode)
  51. {
  52. unsigned long htotal, vtotal;
  53. htotal = mode->htotal;
  54. vtotal = mode->vtotal;
  55. if (!htotal || !vtotal)
  56. return 60;
  57. return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
  58. }
  59. static inline int calc_bandwidth(int width, int height, unsigned int vref)
  60. {
  61. return width * height * vref;
  62. }
  63. int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
  64. int x, int y)
  65. {
  66. struct drm_gem_cma_object *cma_obj[3];
  67. unsigned long eba, ubo, vbo;
  68. int active, i;
  69. for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
  70. cma_obj[i] = drm_fb_cma_get_gem_obj(fb, i);
  71. if (!cma_obj[i]) {
  72. DRM_DEBUG_KMS("plane %d entry is null.\n", i);
  73. return -EFAULT;
  74. }
  75. }
  76. eba = cma_obj[0]->paddr + fb->offsets[0] +
  77. fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
  78. if (eba & 0x7) {
  79. DRM_DEBUG_KMS("base address must be a multiple of 8.\n");
  80. return -EINVAL;
  81. }
  82. if (fb->pitches[0] < 1 || fb->pitches[0] > 16384) {
  83. DRM_DEBUG_KMS("pitches out of range.\n");
  84. return -EINVAL;
  85. }
  86. if (ipu_plane->enabled && fb->pitches[0] != ipu_plane->stride[0]) {
  87. DRM_DEBUG_KMS("pitches must not change while plane is enabled.\n");
  88. return -EINVAL;
  89. }
  90. ipu_plane->stride[0] = fb->pitches[0];
  91. switch (fb->pixel_format) {
  92. case DRM_FORMAT_YUV420:
  93. case DRM_FORMAT_YVU420:
  94. /*
  95. * Multiplanar formats have to meet the following restrictions:
  96. * - The (up to) three plane addresses are EBA, EBA+UBO, EBA+VBO
  97. * - EBA, UBO and VBO are a multiple of 8
  98. * - UBO and VBO are unsigned and not larger than 0xfffff8
  99. * - Only EBA may be changed while scanout is active
  100. * - The strides of U and V planes must be identical.
  101. */
  102. ubo = cma_obj[1]->paddr + fb->offsets[1] +
  103. fb->pitches[1] * y / 2 + x / 2 - eba;
  104. vbo = cma_obj[2]->paddr + fb->offsets[2] +
  105. fb->pitches[2] * y / 2 + x / 2 - eba;
  106. if ((ubo & 0x7) || (vbo & 0x7)) {
  107. DRM_DEBUG_KMS("U/V buffer offsets must be a multiple of 8.\n");
  108. return -EINVAL;
  109. }
  110. if ((ubo > 0xfffff8) || (vbo > 0xfffff8)) {
  111. DRM_DEBUG_KMS("U/V buffer offsets must be positive and not larger than 0xfffff8.\n");
  112. return -EINVAL;
  113. }
  114. if (ipu_plane->enabled && ((ipu_plane->u_offset != ubo) ||
  115. (ipu_plane->v_offset != vbo))) {
  116. DRM_DEBUG_KMS("U/V buffer offsets must not change while plane is enabled.\n");
  117. return -EINVAL;
  118. }
  119. if (fb->pitches[1] != fb->pitches[2]) {
  120. DRM_DEBUG_KMS("U/V pitches must be identical.\n");
  121. return -EINVAL;
  122. }
  123. if (fb->pitches[1] < 1 || fb->pitches[1] > 16384) {
  124. DRM_DEBUG_KMS("U/V pitches out of range.\n");
  125. return -EINVAL;
  126. }
  127. if (ipu_plane->enabled &&
  128. (ipu_plane->stride[1] != fb->pitches[1])) {
  129. DRM_DEBUG_KMS("U/V pitches must not change while plane is enabled.\n");
  130. return -EINVAL;
  131. }
  132. ipu_plane->u_offset = ubo;
  133. ipu_plane->v_offset = vbo;
  134. ipu_plane->stride[1] = fb->pitches[1];
  135. dev_dbg(ipu_plane->base.dev->dev,
  136. "phys = %pad %pad %pad, x = %d, y = %d",
  137. &cma_obj[0]->paddr, &cma_obj[1]->paddr,
  138. &cma_obj[2]->paddr, x, y);
  139. break;
  140. default:
  141. dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
  142. &cma_obj[0]->paddr, x, y);
  143. break;
  144. }
  145. if (ipu_plane->enabled) {
  146. active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
  147. ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
  148. ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
  149. } else {
  150. ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
  151. ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
  152. }
  153. /* cache offsets for subsequent pageflips */
  154. ipu_plane->x = x;
  155. ipu_plane->y = y;
  156. return 0;
  157. }
  158. int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
  159. struct drm_display_mode *mode,
  160. struct drm_framebuffer *fb, int crtc_x, int crtc_y,
  161. unsigned int crtc_w, unsigned int crtc_h,
  162. uint32_t src_x, uint32_t src_y,
  163. uint32_t src_w, uint32_t src_h, bool interlaced)
  164. {
  165. struct device *dev = ipu_plane->base.dev->dev;
  166. int ret;
  167. /* no scaling */
  168. if (src_w != crtc_w || src_h != crtc_h)
  169. return -EINVAL;
  170. /* clip to crtc bounds */
  171. if (crtc_x < 0) {
  172. if (-crtc_x > crtc_w)
  173. return -EINVAL;
  174. src_x += -crtc_x;
  175. src_w -= -crtc_x;
  176. crtc_w -= -crtc_x;
  177. crtc_x = 0;
  178. }
  179. if (crtc_y < 0) {
  180. if (-crtc_y > crtc_h)
  181. return -EINVAL;
  182. src_y += -crtc_y;
  183. src_h -= -crtc_y;
  184. crtc_h -= -crtc_y;
  185. crtc_y = 0;
  186. }
  187. if (crtc_x + crtc_w > mode->hdisplay) {
  188. if (crtc_x > mode->hdisplay)
  189. return -EINVAL;
  190. crtc_w = mode->hdisplay - crtc_x;
  191. src_w = crtc_w;
  192. }
  193. if (crtc_y + crtc_h > mode->vdisplay) {
  194. if (crtc_y > mode->vdisplay)
  195. return -EINVAL;
  196. crtc_h = mode->vdisplay - crtc_y;
  197. src_h = crtc_h;
  198. }
  199. /* full plane minimum width is 13 pixels */
  200. if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
  201. return -EINVAL;
  202. if (crtc_h < 2)
  203. return -EINVAL;
  204. /*
  205. * since we cannot touch active IDMAC channels, we do not support
  206. * resizing the enabled plane or changing its format
  207. */
  208. if (ipu_plane->enabled) {
  209. if (src_w != ipu_plane->w || src_h != ipu_plane->h ||
  210. fb->pixel_format != ipu_plane->base.fb->pixel_format)
  211. return -EINVAL;
  212. return ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
  213. }
  214. switch (ipu_plane->dp_flow) {
  215. case IPU_DP_FLOW_SYNC_BG:
  216. ret = ipu_dp_setup_channel(ipu_plane->dp,
  217. IPUV3_COLORSPACE_RGB,
  218. IPUV3_COLORSPACE_RGB);
  219. if (ret) {
  220. dev_err(dev,
  221. "initializing display processor failed with %d\n",
  222. ret);
  223. return ret;
  224. }
  225. ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
  226. break;
  227. case IPU_DP_FLOW_SYNC_FG:
  228. ipu_dp_setup_channel(ipu_plane->dp,
  229. ipu_drm_fourcc_to_colorspace(fb->pixel_format),
  230. IPUV3_COLORSPACE_UNKNOWN);
  231. ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
  232. /* Enable local alpha on partial plane */
  233. switch (fb->pixel_format) {
  234. case DRM_FORMAT_ARGB1555:
  235. case DRM_FORMAT_ABGR1555:
  236. case DRM_FORMAT_RGBA5551:
  237. case DRM_FORMAT_BGRA5551:
  238. case DRM_FORMAT_ARGB4444:
  239. case DRM_FORMAT_ARGB8888:
  240. case DRM_FORMAT_ABGR8888:
  241. case DRM_FORMAT_RGBA8888:
  242. case DRM_FORMAT_BGRA8888:
  243. ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
  244. break;
  245. default:
  246. break;
  247. }
  248. }
  249. ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
  250. calc_bandwidth(crtc_w, crtc_h,
  251. calc_vref(mode)), 64);
  252. if (ret) {
  253. dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
  254. return ret;
  255. }
  256. ipu_dmfc_config_wait4eot(ipu_plane->dmfc, crtc_w);
  257. ipu_cpmem_zero(ipu_plane->ipu_ch);
  258. ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
  259. ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
  260. if (ret < 0) {
  261. dev_err(dev, "unsupported pixel format 0x%08x\n",
  262. fb->pixel_format);
  263. return ret;
  264. }
  265. ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
  266. ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
  267. ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
  268. ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
  269. if (ret < 0)
  270. return ret;
  271. if (interlaced)
  272. ipu_cpmem_interlaced_scan(ipu_plane->ipu_ch, fb->pitches[0]);
  273. if (fb->pixel_format == DRM_FORMAT_YUV420) {
  274. ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
  275. ipu_plane->stride[1],
  276. ipu_plane->u_offset,
  277. ipu_plane->v_offset);
  278. } else if (fb->pixel_format == DRM_FORMAT_YVU420) {
  279. ipu_cpmem_set_yuv_planar_full(ipu_plane->ipu_ch,
  280. ipu_plane->stride[1],
  281. ipu_plane->v_offset,
  282. ipu_plane->u_offset);
  283. }
  284. ipu_plane->w = src_w;
  285. ipu_plane->h = src_h;
  286. return 0;
  287. }
  288. void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
  289. {
  290. if (!IS_ERR_OR_NULL(ipu_plane->dp))
  291. ipu_dp_put(ipu_plane->dp);
  292. if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
  293. ipu_dmfc_put(ipu_plane->dmfc);
  294. if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
  295. ipu_idmac_put(ipu_plane->ipu_ch);
  296. }
  297. int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
  298. {
  299. int ret;
  300. ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
  301. if (IS_ERR(ipu_plane->ipu_ch)) {
  302. ret = PTR_ERR(ipu_plane->ipu_ch);
  303. DRM_ERROR("failed to get idmac channel: %d\n", ret);
  304. return ret;
  305. }
  306. ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
  307. if (IS_ERR(ipu_plane->dmfc)) {
  308. ret = PTR_ERR(ipu_plane->dmfc);
  309. DRM_ERROR("failed to get dmfc: ret %d\n", ret);
  310. goto err_out;
  311. }
  312. if (ipu_plane->dp_flow >= 0) {
  313. ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
  314. if (IS_ERR(ipu_plane->dp)) {
  315. ret = PTR_ERR(ipu_plane->dp);
  316. DRM_ERROR("failed to get dp flow: %d\n", ret);
  317. goto err_out;
  318. }
  319. }
  320. return 0;
  321. err_out:
  322. ipu_plane_put_resources(ipu_plane);
  323. return ret;
  324. }
  325. void ipu_plane_enable(struct ipu_plane *ipu_plane)
  326. {
  327. if (ipu_plane->dp)
  328. ipu_dp_enable(ipu_plane->ipu);
  329. ipu_dmfc_enable_channel(ipu_plane->dmfc);
  330. ipu_idmac_enable_channel(ipu_plane->ipu_ch);
  331. if (ipu_plane->dp)
  332. ipu_dp_enable_channel(ipu_plane->dp);
  333. ipu_plane->enabled = true;
  334. }
  335. void ipu_plane_disable(struct ipu_plane *ipu_plane)
  336. {
  337. ipu_plane->enabled = false;
  338. ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
  339. if (ipu_plane->dp)
  340. ipu_dp_disable_channel(ipu_plane->dp);
  341. ipu_idmac_disable_channel(ipu_plane->ipu_ch);
  342. ipu_dmfc_disable_channel(ipu_plane->dmfc);
  343. if (ipu_plane->dp)
  344. ipu_dp_disable(ipu_plane->ipu);
  345. }
  346. /*
  347. * drm_plane API
  348. */
  349. static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
  350. struct drm_framebuffer *fb, int crtc_x, int crtc_y,
  351. unsigned int crtc_w, unsigned int crtc_h,
  352. uint32_t src_x, uint32_t src_y,
  353. uint32_t src_w, uint32_t src_h)
  354. {
  355. struct ipu_plane *ipu_plane = to_ipu_plane(plane);
  356. int ret = 0;
  357. DRM_DEBUG_KMS("plane - %p\n", plane);
  358. if (!ipu_plane->enabled)
  359. ret = ipu_plane_get_resources(ipu_plane);
  360. if (ret < 0)
  361. return ret;
  362. ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
  363. crtc_x, crtc_y, crtc_w, crtc_h,
  364. src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16,
  365. false);
  366. if (ret < 0) {
  367. ipu_plane_put_resources(ipu_plane);
  368. return ret;
  369. }
  370. if (crtc != plane->crtc)
  371. dev_dbg(plane->dev->dev, "crtc change: %p -> %p\n",
  372. plane->crtc, crtc);
  373. if (!ipu_plane->enabled)
  374. ipu_plane_enable(ipu_plane);
  375. return 0;
  376. }
  377. static int ipu_disable_plane(struct drm_plane *plane)
  378. {
  379. struct ipu_plane *ipu_plane = to_ipu_plane(plane);
  380. DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
  381. if (ipu_plane->enabled)
  382. ipu_plane_disable(ipu_plane);
  383. ipu_plane_put_resources(ipu_plane);
  384. return 0;
  385. }
  386. static void ipu_plane_destroy(struct drm_plane *plane)
  387. {
  388. struct ipu_plane *ipu_plane = to_ipu_plane(plane);
  389. DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
  390. ipu_disable_plane(plane);
  391. drm_plane_cleanup(plane);
  392. kfree(ipu_plane);
  393. }
  394. static const struct drm_plane_funcs ipu_plane_funcs = {
  395. .update_plane = ipu_update_plane,
  396. .disable_plane = ipu_disable_plane,
  397. .destroy = ipu_plane_destroy,
  398. };
  399. struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
  400. int dma, int dp, unsigned int possible_crtcs,
  401. enum drm_plane_type type)
  402. {
  403. struct ipu_plane *ipu_plane;
  404. int ret;
  405. DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
  406. dma, dp, possible_crtcs);
  407. ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
  408. if (!ipu_plane) {
  409. DRM_ERROR("failed to allocate plane\n");
  410. return ERR_PTR(-ENOMEM);
  411. }
  412. ipu_plane->ipu = ipu;
  413. ipu_plane->dma = dma;
  414. ipu_plane->dp_flow = dp;
  415. ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
  416. &ipu_plane_funcs, ipu_plane_formats,
  417. ARRAY_SIZE(ipu_plane_formats), type,
  418. NULL);
  419. if (ret) {
  420. DRM_ERROR("failed to initialize plane\n");
  421. kfree(ipu_plane);
  422. return ERR_PTR(ret);
  423. }
  424. return ipu_plane;
  425. }