linux/drivers/media/platform/s5p-tv/mixer_grp_layer.c
<<
>>
Prefs
   1/*
   2 * Samsung TV Mixer driver
   3 *
   4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
   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
  16#include <media/videobuf2-dma-contig.h>
  17
  18/* FORMAT DEFINITIONS */
  19
  20static const struct mxr_format mxr_fb_fmt_rgb565 = {
  21        .name = "RGB565",
  22        .fourcc = V4L2_PIX_FMT_RGB565,
  23        .colorspace = V4L2_COLORSPACE_SRGB,
  24        .num_planes = 1,
  25        .plane = {
  26                { .width = 1, .height = 1, .size = 2 },
  27        },
  28        .num_subframes = 1,
  29        .cookie = 4,
  30};
  31
  32static const struct mxr_format mxr_fb_fmt_argb1555 = {
  33        .name = "ARGB1555",
  34        .num_planes = 1,
  35        .fourcc = V4L2_PIX_FMT_RGB555,
  36        .colorspace = V4L2_COLORSPACE_SRGB,
  37        .plane = {
  38                { .width = 1, .height = 1, .size = 2 },
  39        },
  40        .num_subframes = 1,
  41        .cookie = 5,
  42};
  43
  44static const struct mxr_format mxr_fb_fmt_argb4444 = {
  45        .name = "ARGB4444",
  46        .num_planes = 1,
  47        .fourcc = V4L2_PIX_FMT_RGB444,
  48        .colorspace = V4L2_COLORSPACE_SRGB,
  49        .plane = {
  50                { .width = 1, .height = 1, .size = 2 },
  51        },
  52        .num_subframes = 1,
  53        .cookie = 6,
  54};
  55
  56static const struct mxr_format mxr_fb_fmt_argb8888 = {
  57        .name = "ARGB8888",
  58        .fourcc = V4L2_PIX_FMT_BGR32,
  59        .colorspace = V4L2_COLORSPACE_SRGB,
  60        .num_planes = 1,
  61        .plane = {
  62                { .width = 1, .height = 1, .size = 4 },
  63        },
  64        .num_subframes = 1,
  65        .cookie = 7,
  66};
  67
  68static const struct mxr_format *mxr_graph_format[] = {
  69        &mxr_fb_fmt_rgb565,
  70        &mxr_fb_fmt_argb1555,
  71        &mxr_fb_fmt_argb4444,
  72        &mxr_fb_fmt_argb8888,
  73};
  74
  75/* AUXILIARY CALLBACKS */
  76
  77static void mxr_graph_layer_release(struct mxr_layer *layer)
  78{
  79        mxr_base_layer_unregister(layer);
  80        mxr_base_layer_release(layer);
  81}
  82
  83static void mxr_graph_buffer_set(struct mxr_layer *layer,
  84        struct mxr_buffer *buf)
  85{
  86        dma_addr_t addr = 0;
  87
  88        if (buf)
  89                addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
  90        mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
  91}
  92
  93static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
  94{
  95        mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
  96}
  97
  98static void mxr_graph_format_set(struct mxr_layer *layer)
  99{
 100        mxr_reg_graph_format(layer->mdev, layer->idx,
 101                layer->fmt, &layer->geo);
 102}
 103
 104static inline unsigned int closest(unsigned int x, unsigned int a,
 105        unsigned int b, unsigned long flags)
 106{
 107        unsigned int mid = (a + b) / 2;
 108
 109        /* choosing closest value with constraints according to table:
 110         * -------------+-----+-----+-----+-------+
 111         * flags        |  0  |  LE |  GE | LE|GE |
 112         * -------------+-----+-----+-----+-------+
 113         * x <= a       |  a  |  a  |  a  |   a   |
 114         * a < x <= mid |  a  |  a  |  b  |   a   |
 115         * mid < x < b  |  b  |  a  |  b  |   b   |
 116         * b <= x       |  b  |  b  |  b  |   b   |
 117         * -------------+-----+-----+-----+-------+
 118         */
 119
 120        /* remove all non-constraint flags */
 121        flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE;
 122
 123        if (x <= a)
 124                return  a;
 125        if (x >= b)
 126                return b;
 127        if (flags == V4L2_SEL_FLAG_LE)
 128                return a;
 129        if (flags == V4L2_SEL_FLAG_GE)
 130                return b;
 131        if (x <= mid)
 132                return a;
 133        return b;
 134}
 135
 136static inline unsigned int do_center(unsigned int center,
 137        unsigned int size, unsigned int upper, unsigned int flags)
 138{
 139        unsigned int lower;
 140
 141        if (flags & MXR_NO_OFFSET)
 142                return 0;
 143
 144        lower = center - min(center, size / 2);
 145        return min(lower, upper - size);
 146}
 147
 148static void mxr_graph_fix_geometry(struct mxr_layer *layer,
 149        enum mxr_geometry_stage stage, unsigned long flags)
 150{
 151        struct mxr_geometry *geo = &layer->geo;
 152        struct mxr_crop *src = &geo->src;
 153        struct mxr_crop *dst = &geo->dst;
 154        unsigned int x_center, y_center;
 155
 156        switch (stage) {
 157
 158        case MXR_GEOMETRY_SINK: /* nothing to be fixed here */
 159                flags = 0;
 160                /* fall through */
 161
 162        case MXR_GEOMETRY_COMPOSE:
 163                /* remember center of the area */
 164                x_center = dst->x_offset + dst->width / 2;
 165                y_center = dst->y_offset + dst->height / 2;
 166                /* round up/down to 2 multiple depending on flags */
 167                if (flags & V4L2_SEL_FLAG_LE) {
 168                        dst->width = round_down(dst->width, 2);
 169                        dst->height = round_down(dst->height, 2);
 170                } else {
 171                        dst->width = round_up(dst->width, 2);
 172                        dst->height = round_up(dst->height, 2);
 173                }
 174                /* assure that compose rect is inside display area */
 175                dst->width = min(dst->width, dst->full_width);
 176                dst->height = min(dst->height, dst->full_height);
 177
 178                /* ensure that compose is reachable using 2x scaling */
 179                dst->width = min(dst->width, 2 * src->full_width);
 180                dst->height = min(dst->height, 2 * src->full_height);
 181
 182                /* setup offsets */
 183                dst->x_offset = do_center(x_center, dst->width,
 184                        dst->full_width, flags);
 185                dst->y_offset = do_center(y_center, dst->height,
 186                        dst->full_height, flags);
 187                flags = 0;
 188                /* fall through */
 189
 190        case MXR_GEOMETRY_CROP:
 191                /* remember center of the area */
 192                x_center = src->x_offset + src->width / 2;
 193                y_center = src->y_offset + src->height / 2;
 194                /* ensure that cropping area lies inside the buffer */
 195                if (src->full_width < dst->width)
 196                        src->width = dst->width / 2;
 197                else
 198                        src->width = closest(src->width, dst->width / 2,
 199                                dst->width, flags);
 200
 201                if (src->width == dst->width)
 202                        geo->x_ratio = 0;
 203                else
 204                        geo->x_ratio = 1;
 205
 206                if (src->full_height < dst->height)
 207                        src->height = dst->height / 2;
 208                else
 209                        src->height = closest(src->height, dst->height / 2,
 210                                dst->height, flags);
 211
 212                if (src->height == dst->height)
 213                        geo->y_ratio = 0;
 214                else
 215                        geo->y_ratio = 1;
 216
 217                /* setup offsets */
 218                src->x_offset = do_center(x_center, src->width,
 219                        src->full_width, flags);
 220                src->y_offset = do_center(y_center, src->height,
 221                        src->full_height, flags);
 222                flags = 0;
 223                /* fall through */
 224        case MXR_GEOMETRY_SOURCE:
 225                src->full_width = clamp_val(src->full_width,
 226                        src->width + src->x_offset, 32767);
 227                src->full_height = clamp_val(src->full_height,
 228                        src->height + src->y_offset, 2047);
 229        };
 230}
 231
 232/* PUBLIC API */
 233
 234struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
 235{
 236        struct mxr_layer *layer;
 237        int ret;
 238        struct mxr_layer_ops ops = {
 239                .release = mxr_graph_layer_release,
 240                .buffer_set = mxr_graph_buffer_set,
 241                .stream_set = mxr_graph_stream_set,
 242                .format_set = mxr_graph_format_set,
 243                .fix_geometry = mxr_graph_fix_geometry,
 244        };
 245        char name[32];
 246
 247        sprintf(name, "graph%d", idx);
 248
 249        layer = mxr_base_layer_create(mdev, idx, name, &ops);
 250        if (layer == NULL) {
 251                mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
 252                goto fail;
 253        }
 254
 255        layer->fmt_array = mxr_graph_format;
 256        layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
 257
 258        ret = mxr_base_layer_register(layer);
 259        if (ret)
 260                goto fail_layer;
 261
 262        return layer;
 263
 264fail_layer:
 265        mxr_base_layer_release(layer);
 266
 267fail:
 268        return NULL;
 269}
 270
 271