mixer_grp_layer.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Samsung TV Mixer driver
  3. *
  4. * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  5. *
  6. * Tomasz Stanislawski, <t.stanislaws@samsung.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
  10. * by the Free Software Foundiation. either version 2 of the License,
  11. * or (at your option) any later version
  12. */
  13. #include "mixer.h"
  14. #include <media/videobuf2-dma-contig.h>
  15. /* FORMAT DEFINITIONS */
  16. static const struct mxr_format mxr_fb_fmt_rgb565 = {
  17. .name = "RGB565",
  18. .fourcc = V4L2_PIX_FMT_RGB565,
  19. .colorspace = V4L2_COLORSPACE_SRGB,
  20. .num_planes = 1,
  21. .plane = {
  22. { .width = 1, .height = 1, .size = 2 },
  23. },
  24. .num_subframes = 1,
  25. .cookie = 4,
  26. };
  27. static const struct mxr_format mxr_fb_fmt_argb1555 = {
  28. .name = "ARGB1555",
  29. .num_planes = 1,
  30. .fourcc = V4L2_PIX_FMT_RGB555,
  31. .colorspace = V4L2_COLORSPACE_SRGB,
  32. .plane = {
  33. { .width = 1, .height = 1, .size = 2 },
  34. },
  35. .num_subframes = 1,
  36. .cookie = 5,
  37. };
  38. static const struct mxr_format mxr_fb_fmt_argb4444 = {
  39. .name = "ARGB4444",
  40. .num_planes = 1,
  41. .fourcc = V4L2_PIX_FMT_RGB444,
  42. .colorspace = V4L2_COLORSPACE_SRGB,
  43. .plane = {
  44. { .width = 1, .height = 1, .size = 2 },
  45. },
  46. .num_subframes = 1,
  47. .cookie = 6,
  48. };
  49. static const struct mxr_format mxr_fb_fmt_argb8888 = {
  50. .name = "ARGB8888",
  51. .fourcc = V4L2_PIX_FMT_BGR32,
  52. .colorspace = V4L2_COLORSPACE_SRGB,
  53. .num_planes = 1,
  54. .plane = {
  55. { .width = 1, .height = 1, .size = 4 },
  56. },
  57. .num_subframes = 1,
  58. .cookie = 7,
  59. };
  60. static const struct mxr_format *mxr_graph_format[] = {
  61. &mxr_fb_fmt_rgb565,
  62. &mxr_fb_fmt_argb1555,
  63. &mxr_fb_fmt_argb4444,
  64. &mxr_fb_fmt_argb8888,
  65. };
  66. /* AUXILIARY CALLBACKS */
  67. static void mxr_graph_layer_release(struct mxr_layer *layer)
  68. {
  69. mxr_base_layer_unregister(layer);
  70. mxr_base_layer_release(layer);
  71. }
  72. static void mxr_graph_buffer_set(struct mxr_layer *layer,
  73. struct mxr_buffer *buf)
  74. {
  75. dma_addr_t addr = 0;
  76. if (buf)
  77. addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
  78. mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
  79. }
  80. static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
  81. {
  82. mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
  83. }
  84. static void mxr_graph_format_set(struct mxr_layer *layer)
  85. {
  86. mxr_reg_graph_format(layer->mdev, layer->idx,
  87. layer->fmt, &layer->geo);
  88. }
  89. static inline unsigned int closest(unsigned int x, unsigned int a,
  90. unsigned int b, unsigned long flags)
  91. {
  92. unsigned int mid = (a + b) / 2;
  93. /* choosing closest value with constraints according to table:
  94. * -------------+-----+-----+-----+-------+
  95. * flags | 0 | LE | GE | LE|GE |
  96. * -------------+-----+-----+-----+-------+
  97. * x <= a | a | a | a | a |
  98. * a < x <= mid | a | a | b | a |
  99. * mid < x < b | b | a | b | b |
  100. * b <= x | b | b | b | b |
  101. * -------------+-----+-----+-----+-------+
  102. */
  103. /* remove all non-constraint flags */
  104. flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE;
  105. if (x <= a)
  106. return a;
  107. if (x >= b)
  108. return b;
  109. if (flags == V4L2_SEL_FLAG_LE)
  110. return a;
  111. if (flags == V4L2_SEL_FLAG_GE)
  112. return b;
  113. if (x <= mid)
  114. return a;
  115. return b;
  116. }
  117. static inline unsigned int do_center(unsigned int center,
  118. unsigned int size, unsigned int upper, unsigned int flags)
  119. {
  120. unsigned int lower;
  121. if (flags & MXR_NO_OFFSET)
  122. return 0;
  123. lower = center - min(center, size / 2);
  124. return min(lower, upper - size);
  125. }
  126. static void mxr_graph_fix_geometry(struct mxr_layer *layer,
  127. enum mxr_geometry_stage stage, unsigned long flags)
  128. {
  129. struct mxr_geometry *geo = &layer->geo;
  130. struct mxr_crop *src = &geo->src;
  131. struct mxr_crop *dst = &geo->dst;
  132. unsigned int x_center, y_center;
  133. switch (stage) {
  134. case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
  135. flags = 0;
  136. /* fall through */
  137. case MXR_GEOMETRY_COMPOSE:
  138. /* remember center of the area */
  139. x_center = dst->x_offset + dst->width / 2;
  140. y_center = dst->y_offset + dst->height / 2;
  141. /* round up/down to 2 multiple depending on flags */
  142. if (flags & V4L2_SEL_FLAG_LE) {
  143. dst->width = round_down(dst->width, 2);
  144. dst->height = round_down(dst->height, 2);
  145. } else {
  146. dst->width = round_up(dst->width, 2);
  147. dst->height = round_up(dst->height, 2);
  148. }
  149. /* assure that compose rect is inside display area */
  150. dst->width = min(dst->width, dst->full_width);
  151. dst->height = min(dst->height, dst->full_height);
  152. /* ensure that compose is reachable using 2x scaling */
  153. dst->width = min(dst->width, 2 * src->full_width);
  154. dst->height = min(dst->height, 2 * src->full_height);
  155. /* setup offsets */
  156. dst->x_offset = do_center(x_center, dst->width,
  157. dst->full_width, flags);
  158. dst->y_offset = do_center(y_center, dst->height,
  159. dst->full_height, flags);
  160. flags = 0;
  161. /* fall through */
  162. case MXR_GEOMETRY_CROP:
  163. /* remember center of the area */
  164. x_center = src->x_offset + src->width / 2;
  165. y_center = src->y_offset + src->height / 2;
  166. /* ensure that cropping area lies inside the buffer */
  167. if (src->full_width < dst->width)
  168. src->width = dst->width / 2;
  169. else
  170. src->width = closest(src->width, dst->width / 2,
  171. dst->width, flags);
  172. if (src->width == dst->width)
  173. geo->x_ratio = 0;
  174. else
  175. geo->x_ratio = 1;
  176. if (src->full_height < dst->height)
  177. src->height = dst->height / 2;
  178. else
  179. src->height = closest(src->height, dst->height / 2,
  180. dst->height, flags);
  181. if (src->height == dst->height)
  182. geo->y_ratio = 0;
  183. else
  184. geo->y_ratio = 1;
  185. /* setup offsets */
  186. src->x_offset = do_center(x_center, src->width,
  187. src->full_width, flags);
  188. src->y_offset = do_center(y_center, src->height,
  189. src->full_height, flags);
  190. flags = 0;
  191. /* fall through */
  192. case MXR_GEOMETRY_SOURCE:
  193. src->full_width = clamp_val(src->full_width,
  194. src->width + src->x_offset, 32767);
  195. src->full_height = clamp_val(src->full_height,
  196. src->height + src->y_offset, 2047);
  197. }
  198. }
  199. /* PUBLIC API */
  200. struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
  201. {
  202. struct mxr_layer *layer;
  203. int ret;
  204. struct mxr_layer_ops ops = {
  205. .release = mxr_graph_layer_release,
  206. .buffer_set = mxr_graph_buffer_set,
  207. .stream_set = mxr_graph_stream_set,
  208. .format_set = mxr_graph_format_set,
  209. .fix_geometry = mxr_graph_fix_geometry,
  210. };
  211. char name[32];
  212. sprintf(name, "graph%d", idx);
  213. layer = mxr_base_layer_create(mdev, idx, name, &ops);
  214. if (layer == NULL) {
  215. mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
  216. goto fail;
  217. }
  218. layer->fmt_array = mxr_graph_format;
  219. layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
  220. ret = mxr_base_layer_register(layer);
  221. if (ret)
  222. goto fail_layer;
  223. return layer;
  224. fail_layer:
  225. mxr_base_layer_release(layer);
  226. fail:
  227. return NULL;
  228. }