2 * Samsung TV Mixer driver
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
6 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
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
18 #include <media/videobuf2-dma-contig.h>
20 /* FORMAT DEFINITIONS */
21 static const struct mxr_format mxr_fmt_nv12
= {
23 .fourcc
= V4L2_PIX_FMT_NV12
,
24 .colorspace
= V4L2_COLORSPACE_JPEG
,
27 { .width
= 1, .height
= 1, .size
= 1 },
28 { .width
= 2, .height
= 2, .size
= 2 },
31 .cookie
= VP_MODE_NV12
| VP_MODE_MEM_LINEAR
,
34 static const struct mxr_format mxr_fmt_nv21
= {
36 .fourcc
= V4L2_PIX_FMT_NV21
,
37 .colorspace
= V4L2_COLORSPACE_JPEG
,
40 { .width
= 1, .height
= 1, .size
= 1 },
41 { .width
= 2, .height
= 2, .size
= 2 },
44 .cookie
= VP_MODE_NV21
| VP_MODE_MEM_LINEAR
,
47 static const struct mxr_format mxr_fmt_nv12m
= {
48 .name
= "NV12 (mplane)",
49 .fourcc
= V4L2_PIX_FMT_NV12M
,
50 .colorspace
= V4L2_COLORSPACE_JPEG
,
53 { .width
= 1, .height
= 1, .size
= 1 },
54 { .width
= 2, .height
= 2, .size
= 2 },
57 .plane2subframe
= {0, 1},
58 .cookie
= VP_MODE_NV12
| VP_MODE_MEM_LINEAR
,
61 static const struct mxr_format mxr_fmt_nv12mt
= {
62 .name
= "NV12 tiled (mplane)",
63 .fourcc
= V4L2_PIX_FMT_NV12MT
,
64 .colorspace
= V4L2_COLORSPACE_JPEG
,
67 { .width
= 128, .height
= 32, .size
= 4096 },
68 { .width
= 128, .height
= 32, .size
= 2048 },
71 .plane2subframe
= {0, 1},
72 .cookie
= VP_MODE_NV12
| VP_MODE_MEM_TILED
,
75 static const struct mxr_format
*mxr_video_format
[] = {
82 /* AUXILIARY CALLBACKS */
84 static void mxr_vp_layer_release(struct mxr_layer
*layer
)
86 mxr_base_layer_unregister(layer
);
87 mxr_base_layer_release(layer
);
90 static void mxr_vp_buffer_set(struct mxr_layer
*layer
,
91 struct mxr_buffer
*buf
)
93 dma_addr_t luma_addr
[2] = {0, 0};
94 dma_addr_t chroma_addr
[2] = {0, 0};
97 mxr_reg_vp_buffer(layer
->mdev
, luma_addr
, chroma_addr
);
100 luma_addr
[0] = vb2_dma_contig_plane_dma_addr(&buf
->vb
, 0);
101 if (layer
->fmt
->num_subframes
== 2) {
102 chroma_addr
[0] = vb2_dma_contig_plane_dma_addr(&buf
->vb
, 1);
104 /* FIXME: mxr_get_plane_size compute integer division,
105 * which is slow and should not be performed in interrupt */
106 chroma_addr
[0] = luma_addr
[0] + mxr_get_plane_size(
107 &layer
->fmt
->plane
[0], layer
->geo
.src
.full_width
,
108 layer
->geo
.src
.full_height
);
110 if (layer
->fmt
->cookie
& VP_MODE_MEM_TILED
) {
111 luma_addr
[1] = luma_addr
[0] + 0x40;
112 chroma_addr
[1] = chroma_addr
[0] + 0x40;
114 luma_addr
[1] = luma_addr
[0] + layer
->geo
.src
.full_width
;
115 chroma_addr
[1] = chroma_addr
[0];
117 mxr_reg_vp_buffer(layer
->mdev
, luma_addr
, chroma_addr
);
120 static void mxr_vp_stream_set(struct mxr_layer
*layer
, int en
)
122 mxr_reg_vp_layer_stream(layer
->mdev
, en
);
125 static void mxr_vp_format_set(struct mxr_layer
*layer
)
127 mxr_reg_vp_format(layer
->mdev
, layer
->fmt
, &layer
->geo
);
130 static inline unsigned int do_center(unsigned int center
,
131 unsigned int size
, unsigned int upper
, unsigned int flags
)
135 if (flags
& MXR_NO_OFFSET
)
138 lower
= center
- min(center
, size
/ 2);
139 return min(lower
, upper
- size
);
142 static void mxr_vp_fix_geometry(struct mxr_layer
*layer
,
143 enum mxr_geometry_stage stage
, unsigned long flags
)
145 struct mxr_geometry
*geo
= &layer
->geo
;
146 struct mxr_crop
*src
= &geo
->src
;
147 struct mxr_crop
*dst
= &geo
->dst
;
148 unsigned long x_center
, y_center
;
152 case MXR_GEOMETRY_SINK
: /* nothing to be fixed here */
153 case MXR_GEOMETRY_COMPOSE
:
154 /* remember center of the area */
155 x_center
= dst
->x_offset
+ dst
->width
/ 2;
156 y_center
= dst
->y_offset
+ dst
->height
/ 2;
158 /* ensure that compose is reachable using 16x scaling */
159 dst
->width
= clamp(dst
->width
, 8U, 16 * src
->full_width
);
160 dst
->height
= clamp(dst
->height
, 1U, 16 * src
->full_height
);
163 dst
->x_offset
= do_center(x_center
, dst
->width
,
164 dst
->full_width
, flags
);
165 dst
->y_offset
= do_center(y_center
, dst
->height
,
166 dst
->full_height
, flags
);
167 flags
= 0; /* remove possible MXR_NO_OFFSET flag */
169 case MXR_GEOMETRY_CROP
:
170 /* remember center of the area */
171 x_center
= src
->x_offset
+ src
->width
/ 2;
172 y_center
= src
->y_offset
+ src
->height
/ 2;
174 /* ensure scaling is between 0.25x .. 16x */
175 src
->width
= clamp(src
->width
, round_up(dst
->width
/ 16, 4),
177 src
->height
= clamp(src
->height
, round_up(dst
->height
/ 16, 4),
180 /* hardware limits */
181 src
->width
= clamp(src
->width
, 32U, 2047U);
182 src
->height
= clamp(src
->height
, 4U, 2047U);
185 src
->x_offset
= do_center(x_center
, src
->width
,
186 src
->full_width
, flags
);
187 src
->y_offset
= do_center(y_center
, src
->height
,
188 src
->full_height
, flags
);
190 /* setting scaling ratio */
191 geo
->x_ratio
= (src
->width
<< 16) / dst
->width
;
192 geo
->y_ratio
= (src
->height
<< 16) / dst
->height
;
195 case MXR_GEOMETRY_SOURCE
:
196 src
->full_width
= clamp(src
->full_width
,
197 ALIGN(src
->width
+ src
->x_offset
, 8), 8192U);
198 src
->full_height
= clamp(src
->full_height
,
199 src
->height
+ src
->y_offset
, 8192U);
205 struct mxr_layer
*mxr_vp_layer_create(struct mxr_device
*mdev
, int idx
)
207 struct mxr_layer
*layer
;
209 struct mxr_layer_ops ops
= {
210 .release
= mxr_vp_layer_release
,
211 .buffer_set
= mxr_vp_buffer_set
,
212 .stream_set
= mxr_vp_stream_set
,
213 .format_set
= mxr_vp_format_set
,
214 .fix_geometry
= mxr_vp_fix_geometry
,
218 sprintf(name
, "video%d", idx
);
220 layer
= mxr_base_layer_create(mdev
, idx
, name
, &ops
);
222 mxr_err(mdev
, "failed to initialize layer(%d) base\n", idx
);
226 layer
->fmt_array
= mxr_video_format
;
227 layer
->fmt_array_size
= ARRAY_SIZE(mxr_video_format
);
229 ret
= mxr_base_layer_register(layer
);
236 mxr_base_layer_release(layer
);