upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / s5p-tv / mixer_grp_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 /* FORMAT DEFINITIONS */
20
21 static const struct mxr_format mxr_fb_fmt_rgb565 = {
22         .name = "RGB565",
23         .fourcc = V4L2_PIX_FMT_RGB565,
24         .num_planes = 1,
25         .plane = {
26                 { .pxWidth = 1, .pxHeight = 1, .bSize = 2 },
27         },
28         .num_subframes = 1,
29         .hwCode = 4,
30 };
31
32 static const struct mxr_format mxr_fb_fmt_argb1555 = {
33         .name = "ARGB1555",
34         .num_planes = 1,
35         .fourcc = V4L2_PIX_FMT_RGB555,
36         .plane = {
37                 { .pxWidth = 1, .pxHeight = 1, .bSize = 2 },
38         },
39         .num_subframes = 1,
40         .hwCode = 5,
41 };
42
43 static const struct mxr_format mxr_fb_fmt_argb4444 = {
44         .name = "ARGB4444",
45         .num_planes = 1,
46         .fourcc = V4L2_PIX_FMT_RGB444,
47         .plane = {
48                 { .pxWidth = 1, .pxHeight = 1, .bSize = 2 },
49         },
50         .num_subframes = 1,
51         .hwCode = 6,
52 };
53
54 static const struct mxr_format mxr_fb_fmt_argb8888 = {
55         .name = "ARGB8888",
56         .fourcc = V4L2_PIX_FMT_BGR32,
57         .num_planes = 1,
58         .plane = {
59                 { .pxWidth = 1, .pxHeight = 1, .bSize = 4 },
60         },
61         .num_subframes = 1,
62         .hwCode = 7,
63 };
64
65 static const struct mxr_format *mxr_graph_format[] = {
66         &mxr_fb_fmt_rgb565,
67         &mxr_fb_fmt_argb1555,
68         &mxr_fb_fmt_argb4444,
69         &mxr_fb_fmt_argb8888,
70 };
71
72 /* AUXILIARY CALLBACKS */
73
74 static void mxr_graph_layer_release(struct mxr_layer *layer)
75 {
76         mxr_base_layer_unregister(layer);
77         mxr_base_layer_release(layer);
78 }
79
80 static void mxr_graph_buffer_set(struct mxr_layer *layer,
81         struct mxr_buffer *buf)
82 {
83         dma_addr_t addr = 0;
84         if (buf)
85                 addr = vb2_cma_plane_paddr(&buf->vb, 0);
86         mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
87 }
88
89 static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
90 {
91         mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
92 }
93
94 static void mxr_graph_format_set(struct mxr_layer *layer)
95 {
96         mxr_reg_graph_format(layer->mdev, layer->idx,
97                 layer->fmt, &layer->geo);
98 }
99
100 static void mxr_graph_fix_geometry(struct mxr_layer *layer)
101 {
102         struct mxr_geometry *geo = &layer->geo;
103         /* limit to boundary size */
104         geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
105         geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
106         geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width);
107         geo->src.width = min(geo->src.width, 2047U);
108         /* not possible to crop of Y axis */
109         geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1);
110         geo->src.height = geo->src.full_height - geo->src.y_offset;
111         /* limitting offset */
112         geo->src.x_offset = min(geo->src.x_offset,
113                 geo->src.full_width - geo->src.width);
114
115         /* setting position in output */
116         geo->dst.width = min(geo->dst.width, geo->dst.full_width);
117         geo->dst.height = min(geo->dst.height, geo->dst.full_height);
118
119         /* Mixer supports only 1x and 2x scaling */
120         if (geo->dst.width >= 2 * geo->src.width) {
121                 geo->x_ratio = 1;
122                 geo->dst.width = 2 * geo->src.width;
123         } else {
124                 geo->x_ratio = 0;
125                 geo->dst.width = geo->src.width;
126         }
127
128         if (geo->dst.height >= 2 * geo->src.height) {
129                 geo->y_ratio = 1;
130                 geo->dst.height = 2 * geo->src.height;
131         } else {
132                 geo->y_ratio = 0;
133                 geo->dst.height = geo->src.height;
134         }
135
136         geo->dst.x_offset = min(geo->dst.x_offset,
137                 geo->dst.full_width - geo->dst.width);
138         geo->dst.y_offset = min(geo->dst.y_offset,
139                 geo->dst.full_height - geo->dst.height);
140 }
141
142 /* PUBLIC API */
143
144 struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
145 {
146         struct mxr_layer *layer;
147         struct device *dev = mdev->dev;
148         int ret;
149         struct mxr_layer_ops ops = {
150                 .release = mxr_graph_layer_release,
151                 .buffer_set = mxr_graph_buffer_set,
152                 .stream_set = mxr_graph_stream_set,
153                 .format_set = mxr_graph_format_set,
154                 .fix_geometry = mxr_graph_fix_geometry,
155         };
156         char name[32];
157
158         sprintf(name, "graph%d", idx);
159
160         layer = mxr_base_layer_create(mdev, idx, name, &ops);
161         if (layer == NULL) {
162                 dev_err(dev, "failed to initialize layer(%d) base\n", idx);
163                 goto fail;
164         }
165
166         layer->fmt_array = mxr_graph_format;
167         layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
168
169         ret = mxr_base_layer_register(layer);
170         if (ret)
171                 goto fail_layer;
172
173         return layer;
174
175 fail_layer:
176         mxr_base_layer_release(layer);
177
178 fail:
179         return NULL;
180 }
181