vsp1_bru.c 12 KB

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