vsp1_brx.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * vsp1_brx.c -- R-Car VSP1 Blend ROP Unit (BRU and BRS)
  4. *
  5. * Copyright (C) 2013 Renesas Corporation
  6. *
  7. * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  8. */
  9. #include <linux/device.h>
  10. #include <linux/gfp.h>
  11. #include <media/v4l2-subdev.h>
  12. #include "vsp1.h"
  13. #include "vsp1_brx.h"
  14. #include "vsp1_dl.h"
  15. #include "vsp1_pipe.h"
  16. #include "vsp1_rwpf.h"
  17. #include "vsp1_video.h"
  18. #define BRX_MIN_SIZE 1U
  19. #define BRX_MAX_SIZE 8190U
  20. /* -----------------------------------------------------------------------------
  21. * Device Access
  22. */
  23. static inline void vsp1_brx_write(struct vsp1_brx *brx,
  24. struct vsp1_dl_body *dlb, u32 reg, u32 data)
  25. {
  26. vsp1_dl_body_write(dlb, brx->base + reg, data);
  27. }
  28. /* -----------------------------------------------------------------------------
  29. * Controls
  30. */
  31. static int brx_s_ctrl(struct v4l2_ctrl *ctrl)
  32. {
  33. struct vsp1_brx *brx =
  34. container_of(ctrl->handler, struct vsp1_brx, ctrls);
  35. switch (ctrl->id) {
  36. case V4L2_CID_BG_COLOR:
  37. brx->bgcolor = ctrl->val;
  38. break;
  39. }
  40. return 0;
  41. }
  42. static const struct v4l2_ctrl_ops brx_ctrl_ops = {
  43. .s_ctrl = brx_s_ctrl,
  44. };
  45. /* -----------------------------------------------------------------------------
  46. * V4L2 Subdevice Operations
  47. */
  48. /*
  49. * The BRx can't perform format conversion, all sink and source formats must be
  50. * identical. We pick the format on the first sink pad (pad 0) and propagate it
  51. * to all other pads.
  52. */
  53. static int brx_enum_mbus_code(struct v4l2_subdev *subdev,
  54. struct v4l2_subdev_pad_config *cfg,
  55. struct v4l2_subdev_mbus_code_enum *code)
  56. {
  57. static const unsigned int codes[] = {
  58. MEDIA_BUS_FMT_ARGB8888_1X32,
  59. MEDIA_BUS_FMT_AYUV8_1X32,
  60. };
  61. return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
  62. ARRAY_SIZE(codes));
  63. }
  64. static int brx_enum_frame_size(struct v4l2_subdev *subdev,
  65. struct v4l2_subdev_pad_config *cfg,
  66. struct v4l2_subdev_frame_size_enum *fse)
  67. {
  68. if (fse->index)
  69. return -EINVAL;
  70. if (fse->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
  71. fse->code != MEDIA_BUS_FMT_AYUV8_1X32)
  72. return -EINVAL;
  73. fse->min_width = BRX_MIN_SIZE;
  74. fse->max_width = BRX_MAX_SIZE;
  75. fse->min_height = BRX_MIN_SIZE;
  76. fse->max_height = BRX_MAX_SIZE;
  77. return 0;
  78. }
  79. static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
  80. struct v4l2_subdev_pad_config *cfg,
  81. unsigned int pad)
  82. {
  83. return v4l2_subdev_get_try_compose(&brx->entity.subdev, cfg, pad);
  84. }
  85. static void brx_try_format(struct vsp1_brx *brx,
  86. struct v4l2_subdev_pad_config *config,
  87. unsigned int pad, struct v4l2_mbus_framefmt *fmt)
  88. {
  89. struct v4l2_mbus_framefmt *format;
  90. switch (pad) {
  91. case BRX_PAD_SINK(0):
  92. /* Default to YUV if the requested format is not supported. */
  93. if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
  94. fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
  95. fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
  96. break;
  97. default:
  98. /* The BRx can't perform format conversion. */
  99. format = vsp1_entity_get_pad_format(&brx->entity, config,
  100. BRX_PAD_SINK(0));
  101. fmt->code = format->code;
  102. break;
  103. }
  104. fmt->width = clamp(fmt->width, BRX_MIN_SIZE, BRX_MAX_SIZE);
  105. fmt->height = clamp(fmt->height, BRX_MIN_SIZE, BRX_MAX_SIZE);
  106. fmt->field = V4L2_FIELD_NONE;
  107. fmt->colorspace = V4L2_COLORSPACE_SRGB;
  108. }
  109. static int brx_set_format(struct v4l2_subdev *subdev,
  110. struct v4l2_subdev_pad_config *cfg,
  111. struct v4l2_subdev_format *fmt)
  112. {
  113. struct vsp1_brx *brx = to_brx(subdev);
  114. struct v4l2_subdev_pad_config *config;
  115. struct v4l2_mbus_framefmt *format;
  116. int ret = 0;
  117. mutex_lock(&brx->entity.lock);
  118. config = vsp1_entity_get_pad_config(&brx->entity, cfg, fmt->which);
  119. if (!config) {
  120. ret = -EINVAL;
  121. goto done;
  122. }
  123. brx_try_format(brx, config, fmt->pad, &fmt->format);
  124. format = vsp1_entity_get_pad_format(&brx->entity, config, fmt->pad);
  125. *format = fmt->format;
  126. /* Reset the compose rectangle */
  127. if (fmt->pad != brx->entity.source_pad) {
  128. struct v4l2_rect *compose;
  129. compose = brx_get_compose(brx, config, fmt->pad);
  130. compose->left = 0;
  131. compose->top = 0;
  132. compose->width = format->width;
  133. compose->height = format->height;
  134. }
  135. /* Propagate the format code to all pads */
  136. if (fmt->pad == BRX_PAD_SINK(0)) {
  137. unsigned int i;
  138. for (i = 0; i <= brx->entity.source_pad; ++i) {
  139. format = vsp1_entity_get_pad_format(&brx->entity,
  140. config, i);
  141. format->code = fmt->format.code;
  142. }
  143. }
  144. done:
  145. mutex_unlock(&brx->entity.lock);
  146. return ret;
  147. }
  148. static int brx_get_selection(struct v4l2_subdev *subdev,
  149. struct v4l2_subdev_pad_config *cfg,
  150. struct v4l2_subdev_selection *sel)
  151. {
  152. struct vsp1_brx *brx = to_brx(subdev);
  153. struct v4l2_subdev_pad_config *config;
  154. if (sel->pad == brx->entity.source_pad)
  155. return -EINVAL;
  156. switch (sel->target) {
  157. case V4L2_SEL_TGT_COMPOSE_BOUNDS:
  158. sel->r.left = 0;
  159. sel->r.top = 0;
  160. sel->r.width = BRX_MAX_SIZE;
  161. sel->r.height = BRX_MAX_SIZE;
  162. return 0;
  163. case V4L2_SEL_TGT_COMPOSE:
  164. config = vsp1_entity_get_pad_config(&brx->entity, cfg,
  165. sel->which);
  166. if (!config)
  167. return -EINVAL;
  168. mutex_lock(&brx->entity.lock);
  169. sel->r = *brx_get_compose(brx, config, sel->pad);
  170. mutex_unlock(&brx->entity.lock);
  171. return 0;
  172. default:
  173. return -EINVAL;
  174. }
  175. }
  176. static int brx_set_selection(struct v4l2_subdev *subdev,
  177. struct v4l2_subdev_pad_config *cfg,
  178. struct v4l2_subdev_selection *sel)
  179. {
  180. struct vsp1_brx *brx = to_brx(subdev);
  181. struct v4l2_subdev_pad_config *config;
  182. struct v4l2_mbus_framefmt *format;
  183. struct v4l2_rect *compose;
  184. int ret = 0;
  185. if (sel->pad == brx->entity.source_pad)
  186. return -EINVAL;
  187. if (sel->target != V4L2_SEL_TGT_COMPOSE)
  188. return -EINVAL;
  189. mutex_lock(&brx->entity.lock);
  190. config = vsp1_entity_get_pad_config(&brx->entity, cfg, sel->which);
  191. if (!config) {
  192. ret = -EINVAL;
  193. goto done;
  194. }
  195. /*
  196. * The compose rectangle top left corner must be inside the output
  197. * frame.
  198. */
  199. format = vsp1_entity_get_pad_format(&brx->entity, config,
  200. brx->entity.source_pad);
  201. sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
  202. sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
  203. /*
  204. * Scaling isn't supported, the compose rectangle size must be identical
  205. * to the sink format size.
  206. */
  207. format = vsp1_entity_get_pad_format(&brx->entity, config, sel->pad);
  208. sel->r.width = format->width;
  209. sel->r.height = format->height;
  210. compose = brx_get_compose(brx, config, sel->pad);
  211. *compose = sel->r;
  212. done:
  213. mutex_unlock(&brx->entity.lock);
  214. return ret;
  215. }
  216. static const struct v4l2_subdev_pad_ops brx_pad_ops = {
  217. .init_cfg = vsp1_entity_init_cfg,
  218. .enum_mbus_code = brx_enum_mbus_code,
  219. .enum_frame_size = brx_enum_frame_size,
  220. .get_fmt = vsp1_subdev_get_pad_format,
  221. .set_fmt = brx_set_format,
  222. .get_selection = brx_get_selection,
  223. .set_selection = brx_set_selection,
  224. };
  225. static const struct v4l2_subdev_ops brx_ops = {
  226. .pad = &brx_pad_ops,
  227. };
  228. /* -----------------------------------------------------------------------------
  229. * VSP1 Entity Operations
  230. */
  231. static void brx_configure_stream(struct vsp1_entity *entity,
  232. struct vsp1_pipeline *pipe,
  233. struct vsp1_dl_body *dlb)
  234. {
  235. struct vsp1_brx *brx = to_brx(&entity->subdev);
  236. struct v4l2_mbus_framefmt *format;
  237. unsigned int flags;
  238. unsigned int i;
  239. format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.config,
  240. brx->entity.source_pad);
  241. /*
  242. * The hardware is extremely flexible but we have no userspace API to
  243. * expose all the parameters, nor is it clear whether we would have use
  244. * cases for all the supported modes. Let's just harcode the parameters
  245. * to sane default values for now.
  246. */
  247. /*
  248. * Disable dithering and enable color data normalization unless the
  249. * format at the pipeline output is premultiplied.
  250. */
  251. flags = pipe->output ? pipe->output->format.flags : 0;
  252. vsp1_brx_write(brx, dlb, VI6_BRU_INCTRL,
  253. flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
  254. 0 : VI6_BRU_INCTRL_NRM);
  255. /*
  256. * Set the background position to cover the whole output image and
  257. * configure its color.
  258. */
  259. vsp1_brx_write(brx, dlb, VI6_BRU_VIRRPF_SIZE,
  260. (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
  261. (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
  262. vsp1_brx_write(brx, dlb, VI6_BRU_VIRRPF_LOC, 0);
  263. vsp1_brx_write(brx, dlb, VI6_BRU_VIRRPF_COL, brx->bgcolor |
  264. (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
  265. /*
  266. * Route BRU input 1 as SRC input to the ROP unit and configure the ROP
  267. * unit with a NOP operation to make BRU input 1 available as the
  268. * Blend/ROP unit B SRC input. Only needed for BRU, the BRS has no ROP
  269. * unit.
  270. */
  271. if (entity->type == VSP1_ENTITY_BRU)
  272. vsp1_brx_write(brx, dlb, VI6_BRU_ROP,
  273. VI6_BRU_ROP_DSTSEL_BRUIN(1) |
  274. VI6_BRU_ROP_CROP(VI6_ROP_NOP) |
  275. VI6_BRU_ROP_AROP(VI6_ROP_NOP));
  276. for (i = 0; i < brx->entity.source_pad; ++i) {
  277. bool premultiplied = false;
  278. u32 ctrl = 0;
  279. /*
  280. * Configure all Blend/ROP units corresponding to an enabled BRx
  281. * input for alpha blending. Blend/ROP units corresponding to
  282. * disabled BRx inputs are used in ROP NOP mode to ignore the
  283. * SRC input.
  284. */
  285. if (brx->inputs[i].rpf) {
  286. ctrl |= VI6_BRU_CTRL_RBC;
  287. premultiplied = brx->inputs[i].rpf->format.flags
  288. & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
  289. } else {
  290. ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
  291. | VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
  292. }
  293. /*
  294. * Select the virtual RPF as the Blend/ROP unit A DST input to
  295. * serve as a background color.
  296. */
  297. if (i == 0)
  298. ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF;
  299. /*
  300. * Route inputs 0 to 3 as SRC inputs to Blend/ROP units A to D
  301. * in that order. In the BRU the Blend/ROP unit B SRC is
  302. * hardwired to the ROP unit output, the corresponding register
  303. * bits must be set to 0. The BRS has no ROP unit and doesn't
  304. * need any special processing.
  305. */
  306. if (!(entity->type == VSP1_ENTITY_BRU && i == 1))
  307. ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i);
  308. vsp1_brx_write(brx, dlb, VI6_BRU_CTRL(i), ctrl);
  309. /*
  310. * Harcode the blending formula to
  311. *
  312. * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
  313. * DSTa = DSTa * (1 - SRCa) + SRCa
  314. *
  315. * when the SRC input isn't premultiplied, and to
  316. *
  317. * DSTc = DSTc * (1 - SRCa) + SRCc
  318. * DSTa = DSTa * (1 - SRCa) + SRCa
  319. *
  320. * otherwise.
  321. */
  322. vsp1_brx_write(brx, dlb, VI6_BRU_BLD(i),
  323. VI6_BRU_BLD_CCMDX_255_SRC_A |
  324. (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
  325. VI6_BRU_BLD_CCMDY_SRC_A) |
  326. VI6_BRU_BLD_ACMDX_255_SRC_A |
  327. VI6_BRU_BLD_ACMDY_COEFY |
  328. (0xff << VI6_BRU_BLD_COEFY_SHIFT));
  329. }
  330. }
  331. static const struct vsp1_entity_operations brx_entity_ops = {
  332. .configure_stream = brx_configure_stream,
  333. };
  334. /* -----------------------------------------------------------------------------
  335. * Initialization and Cleanup
  336. */
  337. struct vsp1_brx *vsp1_brx_create(struct vsp1_device *vsp1,
  338. enum vsp1_entity_type type)
  339. {
  340. struct vsp1_brx *brx;
  341. unsigned int num_pads;
  342. const char *name;
  343. int ret;
  344. brx = devm_kzalloc(vsp1->dev, sizeof(*brx), GFP_KERNEL);
  345. if (brx == NULL)
  346. return ERR_PTR(-ENOMEM);
  347. brx->base = type == VSP1_ENTITY_BRU ? VI6_BRU_BASE : VI6_BRS_BASE;
  348. brx->entity.ops = &brx_entity_ops;
  349. brx->entity.type = type;
  350. if (type == VSP1_ENTITY_BRU) {
  351. num_pads = vsp1->info->num_bru_inputs + 1;
  352. name = "bru";
  353. } else {
  354. num_pads = 3;
  355. name = "brs";
  356. }
  357. ret = vsp1_entity_init(vsp1, &brx->entity, name, num_pads, &brx_ops,
  358. MEDIA_ENT_F_PROC_VIDEO_COMPOSER);
  359. if (ret < 0)
  360. return ERR_PTR(ret);
  361. /* Initialize the control handler. */
  362. v4l2_ctrl_handler_init(&brx->ctrls, 1);
  363. v4l2_ctrl_new_std(&brx->ctrls, &brx_ctrl_ops, V4L2_CID_BG_COLOR,
  364. 0, 0xffffff, 1, 0);
  365. brx->bgcolor = 0;
  366. brx->entity.subdev.ctrl_handler = &brx->ctrls;
  367. if (brx->ctrls.error) {
  368. dev_err(vsp1->dev, "%s: failed to initialize controls\n", name);
  369. ret = brx->ctrls.error;
  370. vsp1_entity_destroy(&brx->entity);
  371. return ERR_PTR(ret);
  372. }
  373. return brx;
  374. }