vsp1_pipe.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * vsp1_pipe.c -- R-Car VSP1 Pipeline
  3. *
  4. * Copyright (C) 2013-2015 Renesas Electronics Corporation
  5. *
  6. * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/delay.h>
  14. #include <linux/list.h>
  15. #include <linux/sched.h>
  16. #include <linux/wait.h>
  17. #include <media/media-entity.h>
  18. #include <media/v4l2-subdev.h>
  19. #include "vsp1.h"
  20. #include "vsp1_bru.h"
  21. #include "vsp1_dl.h"
  22. #include "vsp1_entity.h"
  23. #include "vsp1_pipe.h"
  24. #include "vsp1_rwpf.h"
  25. #include "vsp1_uds.h"
  26. /* -----------------------------------------------------------------------------
  27. * Helper Functions
  28. */
  29. static const struct vsp1_format_info vsp1_video_formats[] = {
  30. { V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32,
  31. VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  32. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  33. 1, { 8, 0, 0 }, false, false, 1, 1, false },
  34. { V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
  35. VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  36. VI6_RPF_DSWAP_P_WDS,
  37. 1, { 16, 0, 0 }, false, false, 1, 1, true },
  38. { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
  39. VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  40. VI6_RPF_DSWAP_P_WDS,
  41. 1, { 16, 0, 0 }, false, false, 1, 1, false },
  42. { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
  43. VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  44. VI6_RPF_DSWAP_P_WDS,
  45. 1, { 16, 0, 0 }, false, false, 1, 1, true },
  46. { V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
  47. VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  48. VI6_RPF_DSWAP_P_WDS,
  49. 1, { 16, 0, 0 }, false, false, 1, 1, false },
  50. { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32,
  51. VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  52. VI6_RPF_DSWAP_P_WDS,
  53. 1, { 16, 0, 0 }, false, false, 1, 1, false },
  54. { V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32,
  55. VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  56. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  57. 1, { 24, 0, 0 }, false, false, 1, 1, false },
  58. { V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32,
  59. VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  60. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  61. 1, { 24, 0, 0 }, false, false, 1, 1, false },
  62. { V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
  63. VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
  64. 1, { 32, 0, 0 }, false, false, 1, 1, true },
  65. { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
  66. VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
  67. 1, { 32, 0, 0 }, false, false, 1, 1, false },
  68. { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
  69. VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  70. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  71. 1, { 32, 0, 0 }, false, false, 1, 1, true },
  72. { V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
  73. VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  74. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  75. 1, { 32, 0, 0 }, false, false, 1, 1, false },
  76. { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
  77. VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  78. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  79. 1, { 16, 0, 0 }, false, false, 2, 1, false },
  80. { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
  81. VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  82. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  83. 1, { 16, 0, 0 }, false, true, 2, 1, false },
  84. { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32,
  85. VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  86. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  87. 1, { 16, 0, 0 }, true, false, 2, 1, false },
  88. { V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32,
  89. VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  90. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  91. 1, { 16, 0, 0 }, true, true, 2, 1, false },
  92. { V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32,
  93. VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  94. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  95. 2, { 8, 16, 0 }, false, false, 2, 2, false },
  96. { V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32,
  97. VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  98. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  99. 2, { 8, 16, 0 }, false, true, 2, 2, false },
  100. { V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32,
  101. VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  102. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  103. 2, { 8, 16, 0 }, false, false, 2, 1, false },
  104. { V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32,
  105. VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  106. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  107. 2, { 8, 16, 0 }, false, true, 2, 1, false },
  108. { V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32,
  109. VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  110. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  111. 3, { 8, 8, 8 }, false, false, 2, 2, false },
  112. { V4L2_PIX_FMT_YVU420M, MEDIA_BUS_FMT_AYUV8_1X32,
  113. VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  114. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  115. 3, { 8, 8, 8 }, false, true, 2, 2, false },
  116. { V4L2_PIX_FMT_YUV422M, MEDIA_BUS_FMT_AYUV8_1X32,
  117. VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  118. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  119. 3, { 8, 8, 8 }, false, false, 2, 1, false },
  120. { V4L2_PIX_FMT_YVU422M, MEDIA_BUS_FMT_AYUV8_1X32,
  121. VI6_FMT_Y_U_V_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  122. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  123. 3, { 8, 8, 8 }, false, true, 2, 1, false },
  124. { V4L2_PIX_FMT_YUV444M, MEDIA_BUS_FMT_AYUV8_1X32,
  125. VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  126. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  127. 3, { 8, 8, 8 }, false, false, 1, 1, false },
  128. { V4L2_PIX_FMT_YVU444M, MEDIA_BUS_FMT_AYUV8_1X32,
  129. VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
  130. VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
  131. 3, { 8, 8, 8 }, false, true, 1, 1, false },
  132. };
  133. /**
  134. * vsp1_get_format_info - Retrieve format information for a 4CC
  135. * @vsp1: the VSP1 device
  136. * @fourcc: the format 4CC
  137. *
  138. * Return a pointer to the format information structure corresponding to the
  139. * given V4L2 format 4CC, or NULL if no corresponding format can be found.
  140. */
  141. const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
  142. u32 fourcc)
  143. {
  144. unsigned int i;
  145. /* Special case, the VYUY format is supported on Gen2 only. */
  146. if (vsp1->info->gen != 2 && fourcc == V4L2_PIX_FMT_VYUY)
  147. return NULL;
  148. for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) {
  149. const struct vsp1_format_info *info = &vsp1_video_formats[i];
  150. if (info->fourcc == fourcc)
  151. return info;
  152. }
  153. return NULL;
  154. }
  155. /* -----------------------------------------------------------------------------
  156. * Pipeline Management
  157. */
  158. void vsp1_pipeline_reset(struct vsp1_pipeline *pipe)
  159. {
  160. unsigned int i;
  161. if (pipe->bru) {
  162. struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
  163. for (i = 0; i < ARRAY_SIZE(bru->inputs); ++i)
  164. bru->inputs[i].rpf = NULL;
  165. }
  166. for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) {
  167. if (pipe->inputs[i]) {
  168. pipe->inputs[i]->pipe = NULL;
  169. pipe->inputs[i] = NULL;
  170. }
  171. }
  172. if (pipe->output) {
  173. pipe->output->pipe = NULL;
  174. pipe->output = NULL;
  175. }
  176. INIT_LIST_HEAD(&pipe->entities);
  177. pipe->state = VSP1_PIPELINE_STOPPED;
  178. pipe->buffers_ready = 0;
  179. pipe->num_inputs = 0;
  180. pipe->bru = NULL;
  181. pipe->lif = NULL;
  182. pipe->uds = NULL;
  183. }
  184. void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
  185. {
  186. mutex_init(&pipe->lock);
  187. spin_lock_init(&pipe->irqlock);
  188. init_waitqueue_head(&pipe->wq);
  189. kref_init(&pipe->kref);
  190. INIT_LIST_HEAD(&pipe->entities);
  191. pipe->state = VSP1_PIPELINE_STOPPED;
  192. }
  193. /* Must be called with the pipe irqlock held. */
  194. void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
  195. {
  196. struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
  197. if (pipe->state == VSP1_PIPELINE_STOPPED) {
  198. vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index),
  199. VI6_CMD_STRCMD);
  200. pipe->state = VSP1_PIPELINE_RUNNING;
  201. }
  202. pipe->buffers_ready = 0;
  203. }
  204. bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
  205. {
  206. unsigned long flags;
  207. bool stopped;
  208. spin_lock_irqsave(&pipe->irqlock, flags);
  209. stopped = pipe->state == VSP1_PIPELINE_STOPPED;
  210. spin_unlock_irqrestore(&pipe->irqlock, flags);
  211. return stopped;
  212. }
  213. int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
  214. {
  215. struct vsp1_entity *entity;
  216. unsigned long flags;
  217. int ret;
  218. if (pipe->lif) {
  219. /* When using display lists in continuous frame mode the only
  220. * way to stop the pipeline is to reset the hardware.
  221. */
  222. ret = vsp1_reset_wpf(pipe->output->entity.vsp1,
  223. pipe->output->entity.index);
  224. if (ret == 0) {
  225. spin_lock_irqsave(&pipe->irqlock, flags);
  226. pipe->state = VSP1_PIPELINE_STOPPED;
  227. spin_unlock_irqrestore(&pipe->irqlock, flags);
  228. }
  229. } else {
  230. /* Otherwise just request a stop and wait. */
  231. spin_lock_irqsave(&pipe->irqlock, flags);
  232. if (pipe->state == VSP1_PIPELINE_RUNNING)
  233. pipe->state = VSP1_PIPELINE_STOPPING;
  234. spin_unlock_irqrestore(&pipe->irqlock, flags);
  235. ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
  236. msecs_to_jiffies(500));
  237. ret = ret == 0 ? -ETIMEDOUT : 0;
  238. }
  239. list_for_each_entry(entity, &pipe->entities, list_pipe) {
  240. if (entity->route && entity->route->reg)
  241. vsp1_write(entity->vsp1, entity->route->reg,
  242. VI6_DPR_NODE_UNUSED);
  243. }
  244. v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0);
  245. return ret;
  246. }
  247. bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
  248. {
  249. unsigned int mask;
  250. mask = ((1 << pipe->num_inputs) - 1) << 1;
  251. if (!pipe->lif)
  252. mask |= 1 << 0;
  253. return pipe->buffers_ready == mask;
  254. }
  255. void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
  256. {
  257. if (pipe == NULL)
  258. return;
  259. vsp1_dlm_irq_frame_end(pipe->output->dlm);
  260. if (pipe->frame_end)
  261. pipe->frame_end(pipe);
  262. pipe->sequence++;
  263. }
  264. /*
  265. * Propagate the alpha value through the pipeline.
  266. *
  267. * As the UDS has restricted scaling capabilities when the alpha component needs
  268. * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
  269. * value. The UDS then outputs a fixed alpha value which needs to be programmed
  270. * from the input RPF alpha.
  271. */
  272. void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
  273. struct vsp1_dl_list *dl, unsigned int alpha)
  274. {
  275. if (!pipe->uds)
  276. return;
  277. /* The BRU background color has a fixed alpha value set to 255, the
  278. * output alpha value is thus always equal to 255.
  279. */
  280. if (pipe->uds_input->type == VSP1_ENTITY_BRU)
  281. alpha = 255;
  282. vsp1_uds_set_alpha(pipe->uds, dl, alpha);
  283. }
  284. void vsp1_pipelines_suspend(struct vsp1_device *vsp1)
  285. {
  286. unsigned long flags;
  287. unsigned int i;
  288. int ret;
  289. /* To avoid increasing the system suspend time needlessly, loop over the
  290. * pipelines twice, first to set them all to the stopping state, and
  291. * then to wait for the stop to complete.
  292. */
  293. for (i = 0; i < vsp1->info->wpf_count; ++i) {
  294. struct vsp1_rwpf *wpf = vsp1->wpf[i];
  295. struct vsp1_pipeline *pipe;
  296. if (wpf == NULL)
  297. continue;
  298. pipe = wpf->pipe;
  299. if (pipe == NULL)
  300. continue;
  301. spin_lock_irqsave(&pipe->irqlock, flags);
  302. if (pipe->state == VSP1_PIPELINE_RUNNING)
  303. pipe->state = VSP1_PIPELINE_STOPPING;
  304. spin_unlock_irqrestore(&pipe->irqlock, flags);
  305. }
  306. for (i = 0; i < vsp1->info->wpf_count; ++i) {
  307. struct vsp1_rwpf *wpf = vsp1->wpf[i];
  308. struct vsp1_pipeline *pipe;
  309. if (wpf == NULL)
  310. continue;
  311. pipe = wpf->pipe;
  312. if (pipe == NULL)
  313. continue;
  314. ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe),
  315. msecs_to_jiffies(500));
  316. if (ret == 0)
  317. dev_warn(vsp1->dev, "pipeline %u stop timeout\n",
  318. wpf->entity.index);
  319. }
  320. }
  321. void vsp1_pipelines_resume(struct vsp1_device *vsp1)
  322. {
  323. unsigned long flags;
  324. unsigned int i;
  325. /* Resume all running pipelines. */
  326. for (i = 0; i < vsp1->info->wpf_count; ++i) {
  327. struct vsp1_rwpf *wpf = vsp1->wpf[i];
  328. struct vsp1_pipeline *pipe;
  329. if (wpf == NULL)
  330. continue;
  331. pipe = wpf->pipe;
  332. if (pipe == NULL)
  333. continue;
  334. spin_lock_irqsave(&pipe->irqlock, flags);
  335. if (vsp1_pipeline_ready(pipe))
  336. vsp1_pipeline_run(pipe);
  337. spin_unlock_irqrestore(&pipe->irqlock, flags);
  338. }
  339. }