vsp1_sru.c 9.6 KB

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