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_paddr(&buf
->vb
, 0);
101 if (layer
->fmt
->num_subframes
== 2) {
102 chroma_addr
[0] = vb2_dma_contig_plane_paddr(&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 void mxr_vp_fix_geometry(struct mxr_layer
*layer
)
132 struct mxr_geometry
*geo
= &layer
->geo
;
134 /* align horizontal size to 8 pixels */
135 geo
->src
.full_width
= ALIGN(geo
->src
.full_width
, 8);
136 /* limit to boundary size */
137 geo
->src
.full_width
= clamp_val(geo
->src
.full_width
, 8, 8192);
138 geo
->src
.full_height
= clamp_val(geo
->src
.full_height
, 1, 8192);
139 geo
->src
.width
= clamp_val(geo
->src
.width
, 32, geo
->src
.full_width
);
140 geo
->src
.width
= min(geo
->src
.width
, 2047U);
141 geo
->src
.height
= clamp_val(geo
->src
.height
, 4, geo
->src
.full_height
);
142 geo
->src
.height
= min(geo
->src
.height
, 2047U);
144 /* setting size of output window */
145 geo
->dst
.width
= clamp_val(geo
->dst
.width
, 8, geo
->dst
.full_width
);
146 geo
->dst
.height
= clamp_val(geo
->dst
.height
, 1, geo
->dst
.full_height
);
148 /* ensure that scaling is in range 1/4x to 16x */
149 if (geo
->src
.width
>= 4 * geo
->dst
.width
)
150 geo
->src
.width
= 4 * geo
->dst
.width
;
151 if (geo
->dst
.width
>= 16 * geo
->src
.width
)
152 geo
->dst
.width
= 16 * geo
->src
.width
;
153 if (geo
->src
.height
>= 4 * geo
->dst
.height
)
154 geo
->src
.height
= 4 * geo
->dst
.height
;
155 if (geo
->dst
.height
>= 16 * geo
->src
.height
)
156 geo
->dst
.height
= 16 * geo
->src
.height
;
158 /* setting scaling ratio */
159 geo
->x_ratio
= (geo
->src
.width
<< 16) / geo
->dst
.width
;
160 geo
->y_ratio
= (geo
->src
.height
<< 16) / geo
->dst
.height
;
163 geo
->src
.x_offset
= min(geo
->src
.x_offset
,
164 geo
->src
.full_width
- geo
->src
.width
);
165 geo
->src
.y_offset
= min(geo
->src
.y_offset
,
166 geo
->src
.full_height
- geo
->src
.height
);
167 geo
->dst
.x_offset
= min(geo
->dst
.x_offset
,
168 geo
->dst
.full_width
- geo
->dst
.width
);
169 geo
->dst
.y_offset
= min(geo
->dst
.y_offset
,
170 geo
->dst
.full_height
- geo
->dst
.height
);
175 struct mxr_layer
*mxr_vp_layer_create(struct mxr_device
*mdev
, int idx
)
177 struct mxr_layer
*layer
;
179 struct mxr_layer_ops ops
= {
180 .release
= mxr_vp_layer_release
,
181 .buffer_set
= mxr_vp_buffer_set
,
182 .stream_set
= mxr_vp_stream_set
,
183 .format_set
= mxr_vp_format_set
,
184 .fix_geometry
= mxr_vp_fix_geometry
,
188 sprintf(name
, "video%d", idx
);
190 layer
= mxr_base_layer_create(mdev
, idx
, name
, &ops
);
192 mxr_err(mdev
, "failed to initialize layer(%d) base\n", idx
);
196 layer
->fmt_array
= mxr_video_format
;
197 layer
->fmt_array_size
= ARRAY_SIZE(mxr_video_format
);
199 ret
= mxr_base_layer_register(layer
);
206 mxr_base_layer_release(layer
);