vsp1_sru.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * vsp1_sru.c -- R-Car VSP1 Super Resolution Unit
  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_pipe.h"
  15. #include "vsp1_sru.h"
  16. #define SRU_MIN_SIZE 4U
  17. #define SRU_MAX_SIZE 8190U
  18. /* -----------------------------------------------------------------------------
  19. * Device Access
  20. */
  21. static inline void vsp1_sru_write(struct vsp1_sru *sru,
  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_SRU_INTENSITY (V4L2_CID_USER_BASE | 0x1001)
  30. struct vsp1_sru_param {
  31. u32 ctrl0;
  32. u32 ctrl2;
  33. };
  34. #define VI6_SRU_CTRL0_PARAMS(p0, p1) \
  35. (((p0) << VI6_SRU_CTRL0_PARAM0_SHIFT) | \
  36. ((p1) << VI6_SRU_CTRL0_PARAM1_SHIFT))
  37. #define VI6_SRU_CTRL2_PARAMS(p6, p7, p8) \
  38. (((p6) << VI6_SRU_CTRL2_PARAM6_SHIFT) | \
  39. ((p7) << VI6_SRU_CTRL2_PARAM7_SHIFT) | \
  40. ((p8) << VI6_SRU_CTRL2_PARAM8_SHIFT))
  41. static const struct vsp1_sru_param vsp1_sru_params[] = {
  42. {
  43. .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
  44. .ctrl2 = VI6_SRU_CTRL2_PARAMS(24, 40, 255),
  45. }, {
  46. .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
  47. .ctrl2 = VI6_SRU_CTRL2_PARAMS(8, 16, 255),
  48. }, {
  49. .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
  50. .ctrl2 = VI6_SRU_CTRL2_PARAMS(36, 60, 255),
  51. }, {
  52. .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
  53. .ctrl2 = VI6_SRU_CTRL2_PARAMS(12, 27, 255),
  54. }, {
  55. .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
  56. .ctrl2 = VI6_SRU_CTRL2_PARAMS(48, 80, 255),
  57. }, {
  58. .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
  59. .ctrl2 = VI6_SRU_CTRL2_PARAMS(16, 36, 255),
  60. },
  61. };
  62. static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
  63. {
  64. struct vsp1_sru *sru =
  65. container_of(ctrl->handler, struct vsp1_sru, ctrls);
  66. switch (ctrl->id) {
  67. case V4L2_CID_VSP1_SRU_INTENSITY:
  68. sru->intensity = ctrl->val;
  69. break;
  70. }
  71. return 0;
  72. }
  73. static const struct v4l2_ctrl_ops sru_ctrl_ops = {
  74. .s_ctrl = sru_s_ctrl,
  75. };
  76. static const struct v4l2_ctrl_config sru_intensity_control = {
  77. .ops = &sru_ctrl_ops,
  78. .id = V4L2_CID_VSP1_SRU_INTENSITY,
  79. .name = "Intensity",
  80. .type = V4L2_CTRL_TYPE_INTEGER,
  81. .min = 1,
  82. .max = 6,
  83. .def = 1,
  84. .step = 1,
  85. };
  86. /* -----------------------------------------------------------------------------
  87. * V4L2 Subdevice Operations
  88. */
  89. static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
  90. struct v4l2_subdev_pad_config *cfg,
  91. struct v4l2_subdev_mbus_code_enum *code)
  92. {
  93. static const unsigned int codes[] = {
  94. MEDIA_BUS_FMT_ARGB8888_1X32,
  95. MEDIA_BUS_FMT_AYUV8_1X32,
  96. };
  97. return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
  98. ARRAY_SIZE(codes));
  99. }
  100. static int sru_enum_frame_size(struct v4l2_subdev *subdev,
  101. struct v4l2_subdev_pad_config *cfg,
  102. struct v4l2_subdev_frame_size_enum *fse)
  103. {
  104. struct vsp1_sru *sru = to_sru(subdev);
  105. struct v4l2_subdev_pad_config *config;
  106. struct v4l2_mbus_framefmt *format;
  107. int ret = 0;
  108. config = vsp1_entity_get_pad_config(&sru->entity, cfg, fse->which);
  109. if (!config)
  110. return -EINVAL;
  111. format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
  112. mutex_lock(&sru->entity.lock);
  113. if (fse->index || fse->code != format->code) {
  114. ret = -EINVAL;
  115. goto done;
  116. }
  117. if (fse->pad == SRU_PAD_SINK) {
  118. fse->min_width = SRU_MIN_SIZE;
  119. fse->max_width = SRU_MAX_SIZE;
  120. fse->min_height = SRU_MIN_SIZE;
  121. fse->max_height = SRU_MAX_SIZE;
  122. } else {
  123. fse->min_width = format->width;
  124. fse->min_height = format->height;
  125. if (format->width <= SRU_MAX_SIZE / 2 &&
  126. format->height <= SRU_MAX_SIZE / 2) {
  127. fse->max_width = format->width * 2;
  128. fse->max_height = format->height * 2;
  129. } else {
  130. fse->max_width = format->width;
  131. fse->max_height = format->height;
  132. }
  133. }
  134. done:
  135. mutex_unlock(&sru->entity.lock);
  136. return ret;
  137. }
  138. static void sru_try_format(struct vsp1_sru *sru,
  139. struct v4l2_subdev_pad_config *config,
  140. unsigned int pad, struct v4l2_mbus_framefmt *fmt)
  141. {
  142. struct v4l2_mbus_framefmt *format;
  143. unsigned int input_area;
  144. unsigned int output_area;
  145. switch (pad) {
  146. case SRU_PAD_SINK:
  147. /* Default to YUV if the requested format is not supported. */
  148. if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
  149. fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
  150. fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
  151. fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE);
  152. fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE);
  153. break;
  154. case SRU_PAD_SOURCE:
  155. /* The SRU can't perform format conversion. */
  156. format = vsp1_entity_get_pad_format(&sru->entity, config,
  157. SRU_PAD_SINK);
  158. fmt->code = format->code;
  159. /*
  160. * We can upscale by 2 in both direction, but not independently.
  161. * Compare the input and output rectangles areas (avoiding
  162. * integer overflows on the output): if the requested output
  163. * area is larger than 1.5^2 the input area upscale by two,
  164. * otherwise don't scale.
  165. */
  166. input_area = format->width * format->height;
  167. output_area = min(fmt->width, SRU_MAX_SIZE)
  168. * min(fmt->height, SRU_MAX_SIZE);
  169. if (fmt->width <= SRU_MAX_SIZE / 2 &&
  170. fmt->height <= SRU_MAX_SIZE / 2 &&
  171. output_area > input_area * 9 / 4) {
  172. fmt->width = format->width * 2;
  173. fmt->height = format->height * 2;
  174. } else {
  175. fmt->width = format->width;
  176. fmt->height = format->height;
  177. }
  178. break;
  179. }
  180. fmt->field = V4L2_FIELD_NONE;
  181. fmt->colorspace = V4L2_COLORSPACE_SRGB;
  182. }
  183. static int sru_set_format(struct v4l2_subdev *subdev,
  184. struct v4l2_subdev_pad_config *cfg,
  185. struct v4l2_subdev_format *fmt)
  186. {
  187. struct vsp1_sru *sru = to_sru(subdev);
  188. struct v4l2_subdev_pad_config *config;
  189. struct v4l2_mbus_framefmt *format;
  190. int ret = 0;
  191. mutex_lock(&sru->entity.lock);
  192. config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
  193. if (!config) {
  194. ret = -EINVAL;
  195. goto done;
  196. }
  197. sru_try_format(sru, config, fmt->pad, &fmt->format);
  198. format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
  199. *format = fmt->format;
  200. if (fmt->pad == SRU_PAD_SINK) {
  201. /* Propagate the format to the source pad. */
  202. format = vsp1_entity_get_pad_format(&sru->entity, config,
  203. SRU_PAD_SOURCE);
  204. *format = fmt->format;
  205. sru_try_format(sru, config, SRU_PAD_SOURCE, format);
  206. }
  207. done:
  208. mutex_unlock(&sru->entity.lock);
  209. return ret;
  210. }
  211. static const struct v4l2_subdev_pad_ops sru_pad_ops = {
  212. .init_cfg = vsp1_entity_init_cfg,
  213. .enum_mbus_code = sru_enum_mbus_code,
  214. .enum_frame_size = sru_enum_frame_size,
  215. .get_fmt = vsp1_subdev_get_pad_format,
  216. .set_fmt = sru_set_format,
  217. };
  218. static const struct v4l2_subdev_ops sru_ops = {
  219. .pad = &sru_pad_ops,
  220. };
  221. /* -----------------------------------------------------------------------------
  222. * VSP1 Entity Operations
  223. */
  224. static void sru_configure_stream(struct vsp1_entity *entity,
  225. struct vsp1_pipeline *pipe,
  226. struct vsp1_dl_body *dlb)
  227. {
  228. const struct vsp1_sru_param *param;
  229. struct vsp1_sru *sru = to_sru(&entity->subdev);
  230. struct v4l2_mbus_framefmt *input;
  231. struct v4l2_mbus_framefmt *output;
  232. u32 ctrl0;
  233. input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  234. SRU_PAD_SINK);
  235. output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  236. SRU_PAD_SOURCE);
  237. if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
  238. ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
  239. | VI6_SRU_CTRL0_PARAM4;
  240. else
  241. ctrl0 = VI6_SRU_CTRL0_PARAM3;
  242. if (input->width != output->width)
  243. ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
  244. param = &vsp1_sru_params[sru->intensity - 1];
  245. ctrl0 |= param->ctrl0;
  246. vsp1_sru_write(sru, dlb, VI6_SRU_CTRL0, ctrl0);
  247. vsp1_sru_write(sru, dlb, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
  248. vsp1_sru_write(sru, dlb, VI6_SRU_CTRL2, param->ctrl2);
  249. }
  250. static unsigned int sru_max_width(struct vsp1_entity *entity,
  251. struct vsp1_pipeline *pipe)
  252. {
  253. struct vsp1_sru *sru = to_sru(&entity->subdev);
  254. struct v4l2_mbus_framefmt *input;
  255. struct v4l2_mbus_framefmt *output;
  256. input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  257. SRU_PAD_SINK);
  258. output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  259. SRU_PAD_SOURCE);
  260. if (input->width != output->width)
  261. return 512;
  262. else
  263. return 256;
  264. }
  265. static void sru_partition(struct vsp1_entity *entity,
  266. struct vsp1_pipeline *pipe,
  267. struct vsp1_partition *partition,
  268. unsigned int partition_idx,
  269. struct vsp1_partition_window *window)
  270. {
  271. struct vsp1_sru *sru = to_sru(&entity->subdev);
  272. struct v4l2_mbus_framefmt *input;
  273. struct v4l2_mbus_framefmt *output;
  274. input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  275. SRU_PAD_SINK);
  276. output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  277. SRU_PAD_SOURCE);
  278. /* Adapt if SRUx2 is enabled */
  279. if (input->width != output->width) {
  280. window->width /= 2;
  281. window->left /= 2;
  282. }
  283. partition->sru = *window;
  284. }
  285. static const struct vsp1_entity_operations sru_entity_ops = {
  286. .configure_stream = sru_configure_stream,
  287. .max_width = sru_max_width,
  288. .partition = sru_partition,
  289. };
  290. /* -----------------------------------------------------------------------------
  291. * Initialization and Cleanup
  292. */
  293. struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
  294. {
  295. struct vsp1_sru *sru;
  296. int ret;
  297. sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL);
  298. if (sru == NULL)
  299. return ERR_PTR(-ENOMEM);
  300. sru->entity.ops = &sru_entity_ops;
  301. sru->entity.type = VSP1_ENTITY_SRU;
  302. ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops,
  303. MEDIA_ENT_F_PROC_VIDEO_SCALER);
  304. if (ret < 0)
  305. return ERR_PTR(ret);
  306. /* Initialize the control handler. */
  307. v4l2_ctrl_handler_init(&sru->ctrls, 1);
  308. v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
  309. sru->intensity = 1;
  310. sru->entity.subdev.ctrl_handler = &sru->ctrls;
  311. if (sru->ctrls.error) {
  312. dev_err(vsp1->dev, "sru: failed to initialize controls\n");
  313. ret = sru->ctrls.error;
  314. vsp1_entity_destroy(&sru->entity);
  315. return ERR_PTR(ret);
  316. }
  317. return sru;
  318. }