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 "regs-vp.h" 17 18#include <media/videobuf2-dma-contig.h> 19 20/* FORMAT DEFINITIONS */ 21static const struct mxr_format mxr_fmt_nv12 = { 22 .name = "NV12", 23 .fourcc = V4L2_PIX_FMT_NV12, 24 .colorspace = V4L2_COLORSPACE_JPEG, 25 .num_planes = 2, 26 .plane = { 27 { .width = 1, .height = 1, .size = 1 }, 28 { .width = 2, .height = 2, .size = 2 }, 29 }, 30 .num_subframes = 1, 31 .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR, 32}; 33 34static const struct mxr_format mxr_fmt_nv21 = { 35 .name = "NV21", 36 .fourcc = V4L2_PIX_FMT_NV21, 37 .colorspace = V4L2_COLORSPACE_JPEG, 38 .num_planes = 2, 39 .plane = { 40 { .width = 1, .height = 1, .size = 1 }, 41 { .width = 2, .height = 2, .size = 2 }, 42 }, 43 .num_subframes = 1, 44 .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR, 45}; 46 47static const struct mxr_format mxr_fmt_nv12m = { 48 .name = "NV12 (mplane)", 49 .fourcc = V4L2_PIX_FMT_NV12M, 50 .colorspace = V4L2_COLORSPACE_JPEG, 51 .num_planes = 2, 52 .plane = { 53 { .width = 1, .height = 1, .size = 1 }, 54 { .width = 2, .height = 2, .size = 2 }, 55 }, 56 .num_subframes = 2, 57 .plane2subframe = {0, 1}, 58 .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR, 59}; 60 61static const struct mxr_format mxr_fmt_nv12mt = { 62 .name = "NV12 tiled (mplane)", 63 .fourcc = V4L2_PIX_FMT_NV12MT, 64 .colorspace = V4L2_COLORSPACE_JPEG, 65 .num_planes = 2, 66 .plane = { 67 { .width = 128, .height = 32, .size = 4096 }, 68 { .width = 128, .height = 32, .size = 2048 }, 69 }, 70 .num_subframes = 2, 71 .plane2subframe = {0, 1}, 72 .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED, 73}; 74 75static const struct mxr_format *mxr_video_format[] = { 76 &mxr_fmt_nv12, 77 &mxr_fmt_nv21, 78 &mxr_fmt_nv12m, 79 &mxr_fmt_nv12mt, 80}; 81 82/* AUXILIARY CALLBACKS */ 83 84static void mxr_vp_layer_release(struct mxr_layer *layer) 85{ 86 mxr_base_layer_unregister(layer); 87 mxr_base_layer_release(layer); 88} 89 90static void mxr_vp_buffer_set(struct mxr_layer *layer, 91 struct mxr_buffer *buf) 92{ 93 dma_addr_t luma_addr[2] = {0, 0}; 94 dma_addr_t chroma_addr[2] = {0, 0}; 95 96 if (buf == NULL) { 97 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr); 98 return; 99 } 100 luma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 0); 101 if (layer->fmt->num_subframes == 2) { 102 chroma_addr[0] = vb2_dma_contig_plane_dma_addr(&buf->vb, 1); 103 } else { 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); 109 } 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; 113 } else { 114 luma_addr[1] = luma_addr[0] + layer->geo.src.full_width; 115 chroma_addr[1] = chroma_addr[0]; 116 } 117 mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr); 118} 119 120static void mxr_vp_stream_set(struct mxr_layer *layer, int en) 121{ 122 mxr_reg_vp_layer_stream(layer->mdev, en); 123} 124 125static void mxr_vp_format_set(struct mxr_layer *layer) 126{ 127 mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo); 128} 129 130static inline unsigned int do_center(unsigned int center, 131 unsigned int size, unsigned int upper, unsigned int flags) 132{ 133 unsigned int lower; 134 135 if (flags & MXR_NO_OFFSET) 136 return 0; 137 138 lower = center - min(center, size / 2); 139 return min(lower, upper - size); 140} 141 142static void mxr_vp_fix_geometry(struct mxr_layer *layer, 143 enum mxr_geometry_stage stage, unsigned long flags) 144{ 145 struct mxr_geometry *geo = &layer->geo; 146 struct mxr_crop *src = &geo->src; 147 struct mxr_crop *dst = &geo->dst; 148 unsigned long x_center, y_center; 149 150 switch (stage) { 151 152 case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ 153 case MXR_GEOMETRY_COMPOSE: 154 /* remember center of the area */ 155 x_center = dst->x_offset + dst->width / 2; 156 y_center = dst->y_offset + dst->height / 2; 157 158 /* ensure that compose is reachable using 16x scaling */ 159 dst->width = clamp(dst->width, 8U, 16 * src->full_width); 160 dst->height = clamp(dst->height, 1U, 16 * src->full_height); 161 162 /* setup offsets */ 163 dst->x_offset = do_center(x_center, dst->width, 164 dst->full_width, flags); 165 dst->y_offset = do_center(y_center, dst->height, 166 dst->full_height, flags); 167 flags = 0; /* remove possible MXR_NO_OFFSET flag */ 168 /* fall through */ 169 case MXR_GEOMETRY_CROP: 170 /* remember center of the area */ 171 x_center = src->x_offset + src->width / 2; 172 y_center = src->y_offset + src->height / 2; 173 174 /* ensure scaling is between 0.25x .. 16x */ 175 src->width = clamp(src->width, round_up(dst->width / 16, 4), 176 dst->width * 4); 177 src->height = clamp(src->height, round_up(dst->height / 16, 4), 178 dst->height * 4); 179 180 /* hardware limits */ 181 src->width = clamp(src->width, 32U, 2047U); 182 src->height = clamp(src->height, 4U, 2047U); 183 184 /* setup offsets */ 185 src->x_offset = do_center(x_center, src->width, 186 src->full_width, flags); 187 src->y_offset = do_center(y_center, src->height, 188 src->full_height, flags); 189 190 /* setting scaling ratio */ 191 geo->x_ratio = (src->width << 16) / dst->width; 192 geo->y_ratio = (src->height << 16) / dst->height; 193 /* fall through */ 194 195 case MXR_GEOMETRY_SOURCE: 196 src->full_width = clamp(src->full_width, 197 ALIGN(src->width + src->x_offset, 8), 8192U); 198 src->full_height = clamp(src->full_height, 199 src->height + src->y_offset, 8192U); 200 } 201} 202 203/* PUBLIC API */ 204 205struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx) 206{ 207 struct mxr_layer *layer; 208 int ret; 209 struct mxr_layer_ops ops = { 210 .release = mxr_vp_layer_release, 211 .buffer_set = mxr_vp_buffer_set, 212 .stream_set = mxr_vp_stream_set, 213 .format_set = mxr_vp_format_set, 214 .fix_geometry = mxr_vp_fix_geometry, 215 }; 216 char name[32]; 217 218 sprintf(name, "video%d", idx); 219 220 layer = mxr_base_layer_create(mdev, idx, name, &ops); 221 if (layer == NULL) { 222 mxr_err(mdev, "failed to initialize layer(%d) base\n", idx); 223 goto fail; 224 } 225 226 layer->fmt_array = mxr_video_format; 227 layer->fmt_array_size = ARRAY_SIZE(mxr_video_format); 228 229 ret = mxr_base_layer_register(layer); 230 if (ret) 231 goto fail_layer; 232 233 return layer; 234 235fail_layer: 236 mxr_base_layer_release(layer); 237 238fail: 239 return NULL; 240} 241 242