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. /* We can upscale by 2 in both direction, but not independently.
  163. * Compare the input and output rectangles areas (avoiding
  164. * integer overflows on the output): if the requested output
  165. * area is larger than 1.5^2 the input area upscale by two,
  166. * otherwise don't scale.
  167. */
  168. input_area = format->width * format->height;
  169. output_area = min(fmt->width, SRU_MAX_SIZE)
  170. * min(fmt->height, SRU_MAX_SIZE);
  171. if (fmt->width <= SRU_MAX_SIZE / 2 &&
  172. fmt->height <= SRU_MAX_SIZE / 2 &&
  173. output_area > input_area * 9 / 4) {
  174. fmt->width = format->width * 2;
  175. fmt->height = format->height * 2;
  176. } else {
  177. fmt->width = format->width;
  178. fmt->height = format->height;
  179. }
  180. break;
  181. }
  182. fmt->field = V4L2_FIELD_NONE;
  183. fmt->colorspace = V4L2_COLORSPACE_SRGB;
  184. }
  185. static int sru_set_format(struct v4l2_subdev *subdev,
  186. struct v4l2_subdev_pad_config *cfg,
  187. struct v4l2_subdev_format *fmt)
  188. {
  189. struct vsp1_sru *sru = to_sru(subdev);
  190. struct v4l2_subdev_pad_config *config;
  191. struct v4l2_mbus_framefmt *format;
  192. int ret = 0;
  193. mutex_lock(&sru->entity.lock);
  194. config = vsp1_entity_get_pad_config(&sru->entity, cfg, fmt->which);
  195. if (!config) {
  196. ret = -EINVAL;
  197. goto done;
  198. }
  199. sru_try_format(sru, config, fmt->pad, &fmt->format);
  200. format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
  201. *format = fmt->format;
  202. if (fmt->pad == SRU_PAD_SINK) {
  203. /* Propagate the format to the source pad. */
  204. format = vsp1_entity_get_pad_format(&sru->entity, config,
  205. SRU_PAD_SOURCE);
  206. *format = fmt->format;
  207. sru_try_format(sru, config, SRU_PAD_SOURCE, format);
  208. }
  209. done:
  210. mutex_unlock(&sru->entity.lock);
  211. return ret;
  212. }
  213. static const struct v4l2_subdev_pad_ops sru_pad_ops = {
  214. .init_cfg = vsp1_entity_init_cfg,
  215. .enum_mbus_code = sru_enum_mbus_code,
  216. .enum_frame_size = sru_enum_frame_size,
  217. .get_fmt = vsp1_subdev_get_pad_format,
  218. .set_fmt = sru_set_format,
  219. };
  220. static const struct v4l2_subdev_ops sru_ops = {
  221. .pad = &sru_pad_ops,
  222. };
  223. /* -----------------------------------------------------------------------------
  224. * VSP1 Entity Operations
  225. */
  226. static void sru_configure(struct vsp1_entity *entity,
  227. struct vsp1_pipeline *pipe,
  228. struct vsp1_dl_list *dl,
  229. enum vsp1_entity_params params)
  230. {
  231. const struct vsp1_sru_param *param;
  232. struct vsp1_sru *sru = to_sru(&entity->subdev);
  233. struct v4l2_mbus_framefmt *input;
  234. struct v4l2_mbus_framefmt *output;
  235. u32 ctrl0;
  236. if (params != VSP1_ENTITY_PARAMS_INIT)
  237. return;
  238. input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  239. SRU_PAD_SINK);
  240. output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  241. SRU_PAD_SOURCE);
  242. if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
  243. ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
  244. | VI6_SRU_CTRL0_PARAM4;
  245. else
  246. ctrl0 = VI6_SRU_CTRL0_PARAM3;
  247. if (input->width != output->width)
  248. ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
  249. param = &vsp1_sru_params[sru->intensity - 1];
  250. ctrl0 |= param->ctrl0;
  251. vsp1_sru_write(sru, dl, VI6_SRU_CTRL0, ctrl0);
  252. vsp1_sru_write(sru, dl, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
  253. vsp1_sru_write(sru, dl, VI6_SRU_CTRL2, param->ctrl2);
  254. }
  255. static unsigned int sru_max_width(struct vsp1_entity *entity,
  256. struct vsp1_pipeline *pipe)
  257. {
  258. struct vsp1_sru *sru = to_sru(&entity->subdev);
  259. struct v4l2_mbus_framefmt *input;
  260. struct v4l2_mbus_framefmt *output;
  261. input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  262. SRU_PAD_SINK);
  263. output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
  264. SRU_PAD_SOURCE);
  265. if (input->width != output->width)
  266. return 512;
  267. else
  268. return 256;
  269. }
  270. static const struct vsp1_entity_operations sru_entity_ops = {
  271. .configure = sru_configure,
  272. .max_width = sru_max_width,
  273. };
  274. /* -----------------------------------------------------------------------------
  275. * Initialization and Cleanup
  276. */
  277. struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
  278. {
  279. struct vsp1_sru *sru;
  280. int ret;
  281. sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL);
  282. if (sru == NULL)
  283. return ERR_PTR(-ENOMEM);
  284. sru->entity.ops = &sru_entity_ops;
  285. sru->entity.type = VSP1_ENTITY_SRU;
  286. ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops,
  287. MEDIA_ENT_F_PROC_VIDEO_SCALER);
  288. if (ret < 0)
  289. return ERR_PTR(ret);
  290. /* Initialize the control handler. */
  291. v4l2_ctrl_handler_init(&sru->ctrls, 1);
  292. v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
  293. sru->intensity = 1;
  294. sru->entity.subdev.ctrl_handler = &sru->ctrls;
  295. if (sru->ctrls.error) {
  296. dev_err(vsp1->dev, "sru: failed to initialize controls\n");
  297. ret = sru->ctrls.error;
  298. vsp1_entity_destroy(&sru->entity);
  299. return ERR_PTR(ret);
  300. }
  301. return sru;
  302. }