upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / s5p-tv / mixer_vp_layer.c
1 /*
2  * Samsung TV Mixer driver
3  *
4  * Copyright (c) 2010 Samsung Electronics
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
14 #include "mixer.h"
15 #include "mixer_reg.h"
16
17 #include <media/videobuf2-cma.h>
18
19 #include "regs-vp.h"
20
21
22 /* FORMAT DEFINITIONS */
23 static const struct mxr_format mxr_fmt_nv12 = {
24         .name = "NV12",
25         .fourcc = V4L2_PIX_FMT_NV12,
26         .num_planes = 2,
27         .plane = {
28                 { .pxWidth = 1, .pxHeight = 1, .bSize = 1 },
29                 { .pxWidth = 2, .pxHeight = 2, .bSize = 2 },
30         },
31         .num_subframes = 1,
32         .hwCode = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
33 };
34
35 static const struct mxr_format mxr_fmt_nv21 = {
36         .name = "NV21",
37         .fourcc = V4L2_PIX_FMT_NV21,
38         .num_planes = 2,
39         .plane = {
40                 { .pxWidth = 1, .pxHeight = 1, .bSize = 1 },
41                 { .pxWidth = 2, .pxHeight = 2, .bSize = 2 },
42         },
43         .num_subframes = 1,
44         .hwCode = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
45 };
46
47 static const struct mxr_format mxr_fmt_nv12m = {
48         .name = "NV12 (mplane)",
49         .fourcc = V4L2_PIX_FMT_NV12M,
50         .num_planes = 2,
51         .plane = {
52                 { .pxWidth = 1, .pxHeight = 1, .bSize = 1 },
53                 { .pxWidth = 2, .pxHeight = 2, .bSize = 2 },
54         },
55         .num_subframes = 2,
56         .plane2subframe = {0, 1},
57         .hwCode = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
58 };
59
60 static const struct mxr_format mxr_fmt_nv12mt = {
61         .name = "NV12 tiled (mplane)",
62         .fourcc = V4L2_PIX_FMT_NV12MT,
63         .num_planes = 2,
64         .plane = {
65                 { .pxWidth = 128, .pxHeight = 32, .bSize = 4096 },
66                 { .pxWidth = 128, .pxHeight = 32, .bSize = 2048 },
67         },
68         .num_subframes = 2,
69         .plane2subframe = {0, 1},
70         .hwCode = VP_MODE_NV12 | VP_MODE_MEM_TILED,
71 };
72
73 static const struct mxr_format *mxr_video_format[] = {
74         &mxr_fmt_nv12,
75         &mxr_fmt_nv21,
76         &mxr_fmt_nv12m,
77         &mxr_fmt_nv12mt,
78 };
79
80 /* AUXILIARY CALLBACKS */
81
82 static void mxr_vp_layer_release(struct mxr_layer *layer)
83 {
84         mxr_base_layer_unregister(layer);
85         mxr_base_layer_release(layer);
86 }
87
88 static void mxr_vp_buffer_set(struct mxr_layer *layer,
89         struct mxr_buffer *buf)
90 {
91         dma_addr_t luma_addr, chroma_addr;
92         if (buf == NULL) {
93                 mxr_reg_vp_buffer(layer->mdev, 0, 0);
94                 return;
95         }
96         luma_addr = vb2_cma_plane_paddr(&buf->vb, 0);
97         if (layer->fmt->num_subframes == 2) {
98                 chroma_addr = vb2_cma_plane_paddr(&buf->vb, 1);
99         } else {
100                 /* FIXME: mxr_get_plane_size compute integer division,
101                  * which is slow and should not be performed in interrupt */
102                 chroma_addr = luma_addr + mxr_get_plane_size(
103                         &layer->fmt->plane[0], layer->geo.src.full_width,
104                         layer->geo.src.full_height);
105         }
106         /*if (layer->fmt->hwCode & MXR_MODE_TILED)
107                 chroma_addr += 0x40;*/
108         mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
109 }
110
111 static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
112 {
113         mxr_reg_vp_layer_stream(layer->mdev, en);
114 }
115
116 static void mxr_vp_format_set(struct mxr_layer *layer)
117 {
118         mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
119 }
120
121 static void mxr_vp_fix_geometry(struct mxr_layer *layer)
122 {
123         struct mxr_geometry *geo = &layer->geo;
124         /* align horizontal size to 8 pixels */
125         geo->src.full_width = ALIGN(geo->src.full_width, 8);
126         /* limit to boundary size */
127         geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
128         geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
129         geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
130         geo->src.width = min(geo->src.width, 2047U);
131         geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
132         geo->src.height = min(geo->src.height, 2047U);
133
134         /* setting size of output window */
135         geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
136         geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
137
138         /* ensure that scaling is in range 1/4x to 16x */
139         if (geo->src.width >= 4 * geo->dst.width)
140                 geo->src.width = 4 * geo->dst.width;
141         if (geo->dst.width >= 16 * geo->src.width)
142                 geo->dst.width = 16 * geo->src.width;
143         if (geo->src.height >= 4 * geo->dst.height)
144                 geo->src.height = 4 * geo->dst.height;
145         if (geo->dst.height >= 16 * geo->src.height)
146                 geo->dst.height = 16 * geo->src.height;
147
148         /* setting scaling ratio */
149         geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
150         geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
151
152         /* adjust offsets */
153         geo->src.x_offset = min(geo->src.x_offset,
154                 geo->src.full_width - geo->src.width);
155         geo->src.y_offset = min(geo->src.y_offset,
156                 geo->src.full_height - geo->src.height);
157         geo->dst.x_offset = min(geo->dst.x_offset,
158                 geo->dst.full_width - geo->dst.width);
159         geo->dst.y_offset = min(geo->dst.y_offset,
160                 geo->dst.full_height - geo->dst.height);
161 }
162
163 /* PUBLIC API */
164
165 struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
166 {
167         struct mxr_layer *layer;
168         struct device *dev = mdev->dev;
169         int ret;
170         struct mxr_layer_ops ops = {
171                 .release = mxr_vp_layer_release,
172                 .buffer_set = mxr_vp_buffer_set,
173                 .stream_set = mxr_vp_stream_set,
174                 .format_set = mxr_vp_format_set,
175                 .fix_geometry = mxr_vp_fix_geometry,
176         };
177         char name[32];
178
179         sprintf(name, "video%d", idx);
180
181         layer = mxr_base_layer_create(mdev, idx, name, &ops);
182         if (layer == NULL) {
183                 dev_err(dev, "failed to initialize layer(%d) base\n", idx);
184                 goto fail;
185         }
186
187         layer->fmt_array = mxr_video_format;
188         layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
189
190         ret = mxr_base_layer_register(layer);
191         if (ret)
192                 goto fail_layer;
193
194         return layer;
195
196 fail_layer:
197         mxr_base_layer_release(layer);
198
199 fail:
200         return NULL;
201 }
202