2 * Samsung TV Mixer driver
4 * Copyright (c) 2010 Samsung Electronics
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
15 #include "mixer_reg.h"
17 #include <media/videobuf2-cma.h>
22 /* FORMAT DEFINITIONS */
23 static const struct mxr_format mxr_fmt_nv12 = {
25 .fourcc = V4L2_PIX_FMT_NV12,
28 { .pxWidth = 1, .pxHeight = 1, .bSize = 1 },
29 { .pxWidth = 2, .pxHeight = 2, .bSize = 2 },
32 .hwCode = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
35 static const struct mxr_format mxr_fmt_nv21 = {
37 .fourcc = V4L2_PIX_FMT_NV21,
40 { .pxWidth = 1, .pxHeight = 1, .bSize = 1 },
41 { .pxWidth = 2, .pxHeight = 2, .bSize = 2 },
44 .hwCode = 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,
52 { .pxWidth = 1, .pxHeight = 1, .bSize = 1 },
53 { .pxWidth = 2, .pxHeight = 2, .bSize = 2 },
56 .plane2subframe = {0, 1},
57 .hwCode = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
60 static const struct mxr_format mxr_fmt_nv12mt = {
61 .name = "NV12 tiled (mplane)",
62 .fourcc = V4L2_PIX_FMT_NV12MT,
65 { .pxWidth = 128, .pxHeight = 32, .bSize = 4096 },
66 { .pxWidth = 128, .pxHeight = 32, .bSize = 2048 },
69 .plane2subframe = {0, 1},
70 .hwCode = VP_MODE_NV12 | VP_MODE_MEM_TILED,
73 static const struct mxr_format *mxr_video_format[] = {
80 /* AUXILIARY CALLBACKS */
82 static void mxr_vp_layer_release(struct mxr_layer *layer)
84 mxr_base_layer_unregister(layer);
85 mxr_base_layer_release(layer);
88 static void mxr_vp_buffer_set(struct mxr_layer *layer,
89 struct mxr_buffer *buf)
91 dma_addr_t luma_addr, chroma_addr;
93 mxr_reg_vp_buffer(layer->mdev, 0, 0);
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);
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);
106 /*if (layer->fmt->hwCode & MXR_MODE_TILED)
107 chroma_addr += 0x40;*/
108 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
111 static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
113 mxr_reg_vp_layer_stream(layer->mdev, en);
116 static void mxr_vp_format_set(struct mxr_layer *layer)
118 mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
121 static void mxr_vp_fix_geometry(struct mxr_layer *layer)
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);
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);
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;
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;
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);
165 struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
167 struct mxr_layer *layer;
168 struct device *dev = mdev->dev;
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,
179 sprintf(name, "video%d", idx);
181 layer = mxr_base_layer_create(mdev, idx, name, &ops);
183 dev_err(dev, "failed to initialize layer(%d) base\n", idx);
187 layer->fmt_array = mxr_video_format;
188 layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
190 ret = mxr_base_layer_register(layer);
197 mxr_base_layer_release(layer);