1/* 2 * vsp1_rwpf.c -- R-Car VSP1 Read and Write Pixel Formatters 3 * 4 * Copyright (C) 2013-2014 Renesas Electronics Corporation 5 * 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.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 by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14#include <media/v4l2-subdev.h> 15 16#include "vsp1.h" 17#include "vsp1_rwpf.h" 18#include "vsp1_video.h" 19 20#define RWPF_MIN_WIDTH 1 21#define RWPF_MIN_HEIGHT 1 22 23/* ----------------------------------------------------------------------------- 24 * V4L2 Subdevice Pad Operations 25 */ 26 27int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, 28 struct v4l2_subdev_pad_config *cfg, 29 struct v4l2_subdev_mbus_code_enum *code) 30{ 31 static const unsigned int codes[] = { 32 MEDIA_BUS_FMT_ARGB8888_1X32, 33 MEDIA_BUS_FMT_AYUV8_1X32, 34 }; 35 36 if (code->index >= ARRAY_SIZE(codes)) 37 return -EINVAL; 38 39 code->code = codes[code->index]; 40 41 return 0; 42} 43 44int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, 45 struct v4l2_subdev_pad_config *cfg, 46 struct v4l2_subdev_frame_size_enum *fse) 47{ 48 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 49 struct v4l2_mbus_framefmt *format; 50 51 format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad, 52 fse->which); 53 54 if (fse->index || fse->code != format->code) 55 return -EINVAL; 56 57 if (fse->pad == RWPF_PAD_SINK) { 58 fse->min_width = RWPF_MIN_WIDTH; 59 fse->max_width = rwpf->max_width; 60 fse->min_height = RWPF_MIN_HEIGHT; 61 fse->max_height = rwpf->max_height; 62 } else { 63 /* The size on the source pad are fixed and always identical to 64 * the size on the sink pad. 65 */ 66 fse->min_width = format->width; 67 fse->max_width = format->width; 68 fse->min_height = format->height; 69 fse->max_height = format->height; 70 } 71 72 return 0; 73} 74 75static struct v4l2_rect * 76vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which) 77{ 78 switch (which) { 79 case V4L2_SUBDEV_FORMAT_TRY: 80 return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK); 81 case V4L2_SUBDEV_FORMAT_ACTIVE: 82 return &rwpf->crop; 83 default: 84 return NULL; 85 } 86} 87 88int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 89 struct v4l2_subdev_format *fmt) 90{ 91 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 92 93 fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, 94 fmt->which); 95 96 return 0; 97} 98 99int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, 100 struct v4l2_subdev_format *fmt) 101{ 102 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 103 struct v4l2_mbus_framefmt *format; 104 struct v4l2_rect *crop; 105 106 /* Default to YUV if the requested format is not supported. */ 107 if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && 108 fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) 109 fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; 110 111 format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, 112 fmt->which); 113 114 if (fmt->pad == RWPF_PAD_SOURCE) { 115 /* The RWPF performs format conversion but can't scale, only the 116 * format code can be changed on the source pad. 117 */ 118 format->code = fmt->format.code; 119 fmt->format = *format; 120 return 0; 121 } 122 123 format->code = fmt->format.code; 124 format->width = clamp_t(unsigned int, fmt->format.width, 125 RWPF_MIN_WIDTH, rwpf->max_width); 126 format->height = clamp_t(unsigned int, fmt->format.height, 127 RWPF_MIN_HEIGHT, rwpf->max_height); 128 format->field = V4L2_FIELD_NONE; 129 format->colorspace = V4L2_COLORSPACE_SRGB; 130 131 fmt->format = *format; 132 133 /* Update the sink crop rectangle. */ 134 crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); 135 crop->left = 0; 136 crop->top = 0; 137 crop->width = fmt->format.width; 138 crop->height = fmt->format.height; 139 140 /* Propagate the format to the source pad. */ 141 format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, 142 fmt->which); 143 *format = fmt->format; 144 145 return 0; 146} 147 148int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, 149 struct v4l2_subdev_pad_config *cfg, 150 struct v4l2_subdev_selection *sel) 151{ 152 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 153 struct v4l2_mbus_framefmt *format; 154 155 /* Cropping is implemented on the sink pad. */ 156 if (sel->pad != RWPF_PAD_SINK) 157 return -EINVAL; 158 159 switch (sel->target) { 160 case V4L2_SEL_TGT_CROP: 161 sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); 162 break; 163 164 case V4L2_SEL_TGT_CROP_BOUNDS: 165 format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, 166 RWPF_PAD_SINK, sel->which); 167 sel->r.left = 0; 168 sel->r.top = 0; 169 sel->r.width = format->width; 170 sel->r.height = format->height; 171 break; 172 173 default: 174 return -EINVAL; 175 } 176 177 return 0; 178} 179 180int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, 181 struct v4l2_subdev_pad_config *cfg, 182 struct v4l2_subdev_selection *sel) 183{ 184 struct vsp1_rwpf *rwpf = to_rwpf(subdev); 185 struct v4l2_mbus_framefmt *format; 186 struct v4l2_rect *crop; 187 188 /* Cropping is implemented on the sink pad. */ 189 if (sel->pad != RWPF_PAD_SINK) 190 return -EINVAL; 191 192 if (sel->target != V4L2_SEL_TGT_CROP) 193 return -EINVAL; 194 195 /* Make sure the crop rectangle is entirely contained in the image. The 196 * WPF top and left offsets are limited to 255. 197 */ 198 format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, 199 sel->which); 200 201 /* Restrict the crop rectangle coordinates to multiples of 2 to avoid 202 * shifting the color plane. 203 */ 204 if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { 205 sel->r.left = ALIGN(sel->r.left, 2); 206 sel->r.top = ALIGN(sel->r.top, 2); 207 sel->r.width = round_down(sel->r.width, 2); 208 sel->r.height = round_down(sel->r.height, 2); 209 } 210 211 sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); 212 sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); 213 if (rwpf->entity.type == VSP1_ENTITY_WPF) { 214 sel->r.left = min_t(unsigned int, sel->r.left, 255); 215 sel->r.top = min_t(unsigned int, sel->r.top, 255); 216 } 217 sel->r.width = min_t(unsigned int, sel->r.width, 218 format->width - sel->r.left); 219 sel->r.height = min_t(unsigned int, sel->r.height, 220 format->height - sel->r.top); 221 222 crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); 223 *crop = sel->r; 224 225 /* Propagate the format to the source pad. */ 226 format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, 227 sel->which); 228 format->width = crop->width; 229 format->height = crop->height; 230 231 return 0; 232} 233