vsp1_hgo.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * vsp1_hgo.c -- R-Car VSP1 Histogram Generator 1D
  3. *
  4. * Copyright (C) 2016 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/device.h>
  14. #include <linux/gfp.h>
  15. #include <media/v4l2-subdev.h>
  16. #include <media/videobuf2-vmalloc.h>
  17. #include "vsp1.h"
  18. #include "vsp1_dl.h"
  19. #include "vsp1_hgo.h"
  20. #define HGO_DATA_SIZE ((2 + 256) * 4)
  21. /* -----------------------------------------------------------------------------
  22. * Device Access
  23. */
  24. static inline u32 vsp1_hgo_read(struct vsp1_hgo *hgo, u32 reg)
  25. {
  26. return vsp1_read(hgo->histo.entity.vsp1, reg);
  27. }
  28. static inline void vsp1_hgo_write(struct vsp1_hgo *hgo, struct vsp1_dl_list *dl,
  29. u32 reg, u32 data)
  30. {
  31. vsp1_dl_list_write(dl, reg, data);
  32. }
  33. /* -----------------------------------------------------------------------------
  34. * Frame End Handler
  35. */
  36. void vsp1_hgo_frame_end(struct vsp1_entity *entity)
  37. {
  38. struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
  39. struct vsp1_histogram_buffer *buf;
  40. unsigned int i;
  41. size_t size;
  42. u32 *data;
  43. buf = vsp1_histogram_buffer_get(&hgo->histo);
  44. if (!buf)
  45. return;
  46. data = buf->addr;
  47. if (hgo->num_bins == 256) {
  48. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
  49. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
  50. for (i = 0; i < 256; ++i) {
  51. vsp1_write(hgo->histo.entity.vsp1,
  52. VI6_HGO_EXT_HIST_ADDR, i);
  53. *data++ = vsp1_hgo_read(hgo, VI6_HGO_EXT_HIST_DATA);
  54. }
  55. size = (2 + 256) * sizeof(u32);
  56. } else if (hgo->max_rgb) {
  57. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
  58. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
  59. for (i = 0; i < 64; ++i)
  60. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i));
  61. size = (2 + 64) * sizeof(u32);
  62. } else {
  63. *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_MAXMIN);
  64. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
  65. *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_MAXMIN);
  66. *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_SUM);
  67. *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
  68. *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_SUM);
  69. for (i = 0; i < 64; ++i) {
  70. data[i] = vsp1_hgo_read(hgo, VI6_HGO_R_HISTO(i));
  71. data[i+64] = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i));
  72. data[i+128] = vsp1_hgo_read(hgo, VI6_HGO_B_HISTO(i));
  73. }
  74. size = (6 + 64 * 3) * sizeof(u32);
  75. }
  76. vsp1_histogram_buffer_complete(&hgo->histo, buf, size);
  77. }
  78. /* -----------------------------------------------------------------------------
  79. * Controls
  80. */
  81. #define V4L2_CID_VSP1_HGO_MAX_RGB (V4L2_CID_USER_BASE | 0x1001)
  82. #define V4L2_CID_VSP1_HGO_NUM_BINS (V4L2_CID_USER_BASE | 0x1002)
  83. static const struct v4l2_ctrl_config hgo_max_rgb_control = {
  84. .id = V4L2_CID_VSP1_HGO_MAX_RGB,
  85. .name = "Maximum RGB Mode",
  86. .type = V4L2_CTRL_TYPE_BOOLEAN,
  87. .min = 0,
  88. .max = 1,
  89. .def = 0,
  90. .step = 1,
  91. };
  92. static const s64 hgo_num_bins[] = {
  93. 64, 256,
  94. };
  95. static const struct v4l2_ctrl_config hgo_num_bins_control = {
  96. .id = V4L2_CID_VSP1_HGO_NUM_BINS,
  97. .name = "Number of Bins",
  98. .type = V4L2_CTRL_TYPE_INTEGER_MENU,
  99. .min = 0,
  100. .max = 1,
  101. .def = 0,
  102. .qmenu_int = hgo_num_bins,
  103. };
  104. /* -----------------------------------------------------------------------------
  105. * VSP1 Entity Operations
  106. */
  107. static void hgo_configure(struct vsp1_entity *entity,
  108. struct vsp1_pipeline *pipe,
  109. struct vsp1_dl_list *dl,
  110. enum vsp1_entity_params params)
  111. {
  112. struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
  113. struct v4l2_rect *compose;
  114. struct v4l2_rect *crop;
  115. unsigned int hratio;
  116. unsigned int vratio;
  117. if (params != VSP1_ENTITY_PARAMS_INIT)
  118. return;
  119. crop = vsp1_entity_get_pad_selection(entity, entity->config,
  120. HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
  121. compose = vsp1_entity_get_pad_selection(entity, entity->config,
  122. HISTO_PAD_SINK,
  123. V4L2_SEL_TGT_COMPOSE);
  124. vsp1_hgo_write(hgo, dl, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA);
  125. vsp1_hgo_write(hgo, dl, VI6_HGO_OFFSET,
  126. (crop->left << VI6_HGO_OFFSET_HOFFSET_SHIFT) |
  127. (crop->top << VI6_HGO_OFFSET_VOFFSET_SHIFT));
  128. vsp1_hgo_write(hgo, dl, VI6_HGO_SIZE,
  129. (crop->width << VI6_HGO_SIZE_HSIZE_SHIFT) |
  130. (crop->height << VI6_HGO_SIZE_VSIZE_SHIFT));
  131. mutex_lock(hgo->ctrls.handler.lock);
  132. hgo->max_rgb = hgo->ctrls.max_rgb->cur.val;
  133. if (hgo->ctrls.num_bins)
  134. hgo->num_bins = hgo_num_bins[hgo->ctrls.num_bins->cur.val];
  135. mutex_unlock(hgo->ctrls.handler.lock);
  136. hratio = crop->width * 2 / compose->width / 3;
  137. vratio = crop->height * 2 / compose->height / 3;
  138. vsp1_hgo_write(hgo, dl, VI6_HGO_MODE,
  139. (hgo->num_bins == 256 ? VI6_HGO_MODE_STEP : 0) |
  140. (hgo->max_rgb ? VI6_HGO_MODE_MAXRGB : 0) |
  141. (hratio << VI6_HGO_MODE_HRATIO_SHIFT) |
  142. (vratio << VI6_HGO_MODE_VRATIO_SHIFT));
  143. }
  144. static const struct vsp1_entity_operations hgo_entity_ops = {
  145. .configure = hgo_configure,
  146. .destroy = vsp1_histogram_destroy,
  147. };
  148. /* -----------------------------------------------------------------------------
  149. * Initialization and Cleanup
  150. */
  151. static const unsigned int hgo_mbus_formats[] = {
  152. MEDIA_BUS_FMT_AYUV8_1X32,
  153. MEDIA_BUS_FMT_ARGB8888_1X32,
  154. MEDIA_BUS_FMT_AHSV8888_1X32,
  155. };
  156. struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
  157. {
  158. struct vsp1_hgo *hgo;
  159. int ret;
  160. hgo = devm_kzalloc(vsp1->dev, sizeof(*hgo), GFP_KERNEL);
  161. if (hgo == NULL)
  162. return ERR_PTR(-ENOMEM);
  163. /* Initialize the control handler. */
  164. v4l2_ctrl_handler_init(&hgo->ctrls.handler,
  165. vsp1->info->gen == 3 ? 2 : 1);
  166. hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler,
  167. &hgo_max_rgb_control, NULL);
  168. if (vsp1->info->gen == 3)
  169. hgo->ctrls.num_bins =
  170. v4l2_ctrl_new_custom(&hgo->ctrls.handler,
  171. &hgo_num_bins_control, NULL);
  172. hgo->max_rgb = false;
  173. hgo->num_bins = 64;
  174. hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler;
  175. /* Initialize the video device and queue for statistics data. */
  176. ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
  177. &hgo_entity_ops, hgo_mbus_formats,
  178. ARRAY_SIZE(hgo_mbus_formats),
  179. HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
  180. if (ret < 0) {
  181. vsp1_entity_destroy(&hgo->histo.entity);
  182. return ERR_PTR(ret);
  183. }
  184. return hgo;
  185. }