vsp1_lut.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * vsp1_lut.c -- R-Car VSP1 Look-Up Table
  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_dl.h"
  14. #include "vsp1_lut.h"
  15. #define LUT_MIN_SIZE 4U
  16. #define LUT_MAX_SIZE 8190U
  17. #define LUT_SIZE 256
  18. /* -----------------------------------------------------------------------------
  19. * Device Access
  20. */
  21. static inline void vsp1_lut_write(struct vsp1_lut *lut,
  22. struct vsp1_dl_body *dlb, u32 reg, u32 data)
  23. {
  24. vsp1_dl_body_write(dlb, reg, data);
  25. }
  26. /* -----------------------------------------------------------------------------
  27. * Controls
  28. */
  29. #define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001)
  30. static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl)
  31. {
  32. struct vsp1_dl_body *dlb;
  33. unsigned int i;
  34. dlb = vsp1_dl_body_get(lut->pool);
  35. if (!dlb)
  36. return -ENOMEM;
  37. for (i = 0; i < LUT_SIZE; ++i)
  38. vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i,
  39. ctrl->p_new.p_u32[i]);
  40. spin_lock_irq(&lut->lock);
  41. swap(lut->lut, dlb);
  42. spin_unlock_irq(&lut->lock);
  43. vsp1_dl_body_put(dlb);
  44. return 0;
  45. }
  46. static int lut_s_ctrl(struct v4l2_ctrl *ctrl)
  47. {
  48. struct vsp1_lut *lut =
  49. container_of(ctrl->handler, struct vsp1_lut, ctrls);
  50. switch (ctrl->id) {
  51. case V4L2_CID_VSP1_LUT_TABLE:
  52. lut_set_table(lut, ctrl);
  53. break;
  54. }
  55. return 0;
  56. }
  57. static const struct v4l2_ctrl_ops lut_ctrl_ops = {
  58. .s_ctrl = lut_s_ctrl,
  59. };
  60. static const struct v4l2_ctrl_config lut_table_control = {
  61. .ops = &lut_ctrl_ops,
  62. .id = V4L2_CID_VSP1_LUT_TABLE,
  63. .name = "Look-Up Table",
  64. .type = V4L2_CTRL_TYPE_U32,
  65. .min = 0x00000000,
  66. .max = 0x00ffffff,
  67. .step = 1,
  68. .def = 0,
  69. .dims = { LUT_SIZE },
  70. };
  71. /* -----------------------------------------------------------------------------
  72. * V4L2 Subdevice Pad Operations
  73. */
  74. static const unsigned int lut_codes[] = {
  75. MEDIA_BUS_FMT_ARGB8888_1X32,
  76. MEDIA_BUS_FMT_AHSV8888_1X32,
  77. MEDIA_BUS_FMT_AYUV8_1X32,
  78. };
  79. static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
  80. struct v4l2_subdev_pad_config *cfg,
  81. struct v4l2_subdev_mbus_code_enum *code)
  82. {
  83. return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lut_codes,
  84. ARRAY_SIZE(lut_codes));
  85. }
  86. static int lut_enum_frame_size(struct v4l2_subdev *subdev,
  87. struct v4l2_subdev_pad_config *cfg,
  88. struct v4l2_subdev_frame_size_enum *fse)
  89. {
  90. return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LUT_MIN_SIZE,
  91. LUT_MIN_SIZE, LUT_MAX_SIZE,
  92. LUT_MAX_SIZE);
  93. }
  94. static int lut_set_format(struct v4l2_subdev *subdev,
  95. struct v4l2_subdev_pad_config *cfg,
  96. struct v4l2_subdev_format *fmt)
  97. {
  98. return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lut_codes,
  99. ARRAY_SIZE(lut_codes),
  100. LUT_MIN_SIZE, LUT_MIN_SIZE,
  101. LUT_MAX_SIZE, LUT_MAX_SIZE);
  102. }
  103. /* -----------------------------------------------------------------------------
  104. * V4L2 Subdevice Operations
  105. */
  106. static const struct v4l2_subdev_pad_ops lut_pad_ops = {
  107. .init_cfg = vsp1_entity_init_cfg,
  108. .enum_mbus_code = lut_enum_mbus_code,
  109. .enum_frame_size = lut_enum_frame_size,
  110. .get_fmt = vsp1_subdev_get_pad_format,
  111. .set_fmt = lut_set_format,
  112. };
  113. static const struct v4l2_subdev_ops lut_ops = {
  114. .pad = &lut_pad_ops,
  115. };
  116. /* -----------------------------------------------------------------------------
  117. * VSP1 Entity Operations
  118. */
  119. static void lut_configure_stream(struct vsp1_entity *entity,
  120. struct vsp1_pipeline *pipe,
  121. struct vsp1_dl_body *dlb)
  122. {
  123. struct vsp1_lut *lut = to_lut(&entity->subdev);
  124. vsp1_lut_write(lut, dlb, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
  125. }
  126. static void lut_configure_frame(struct vsp1_entity *entity,
  127. struct vsp1_pipeline *pipe,
  128. struct vsp1_dl_list *dl,
  129. struct vsp1_dl_body *dlb)
  130. {
  131. struct vsp1_lut *lut = to_lut(&entity->subdev);
  132. struct vsp1_dl_body *lut_dlb;
  133. unsigned long flags;
  134. spin_lock_irqsave(&lut->lock, flags);
  135. lut_dlb = lut->lut;
  136. lut->lut = NULL;
  137. spin_unlock_irqrestore(&lut->lock, flags);
  138. if (lut_dlb) {
  139. vsp1_dl_list_add_body(dl, lut_dlb);
  140. /* Release our local reference. */
  141. vsp1_dl_body_put(lut_dlb);
  142. }
  143. }
  144. static void lut_destroy(struct vsp1_entity *entity)
  145. {
  146. struct vsp1_lut *lut = to_lut(&entity->subdev);
  147. vsp1_dl_body_pool_destroy(lut->pool);
  148. }
  149. static const struct vsp1_entity_operations lut_entity_ops = {
  150. .configure_stream = lut_configure_stream,
  151. .configure_frame = lut_configure_frame,
  152. .destroy = lut_destroy,
  153. };
  154. /* -----------------------------------------------------------------------------
  155. * Initialization and Cleanup
  156. */
  157. struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
  158. {
  159. struct vsp1_lut *lut;
  160. int ret;
  161. lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
  162. if (lut == NULL)
  163. return ERR_PTR(-ENOMEM);
  164. spin_lock_init(&lut->lock);
  165. lut->entity.ops = &lut_entity_ops;
  166. lut->entity.type = VSP1_ENTITY_LUT;
  167. ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
  168. MEDIA_ENT_F_PROC_VIDEO_LUT);
  169. if (ret < 0)
  170. return ERR_PTR(ret);
  171. /*
  172. * Pre-allocate a body pool, with 3 bodies allowing a userspace update
  173. * before the hardware has committed a previous set of tables, handling
  174. * both the queued and pending dl entries.
  175. */
  176. lut->pool = vsp1_dl_body_pool_create(vsp1, 3, LUT_SIZE, 0);
  177. if (!lut->pool)
  178. return ERR_PTR(-ENOMEM);
  179. /* Initialize the control handler. */
  180. v4l2_ctrl_handler_init(&lut->ctrls, 1);
  181. v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
  182. lut->entity.subdev.ctrl_handler = &lut->ctrls;
  183. if (lut->ctrls.error) {
  184. dev_err(vsp1->dev, "lut: failed to initialize controls\n");
  185. ret = lut->ctrls.error;
  186. vsp1_entity_destroy(&lut->entity);
  187. return ERR_PTR(ret);
  188. }
  189. v4l2_ctrl_handler_setup(&lut->ctrls);
  190. return lut;
  191. }