brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · 9d38203 Raw
277 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * vsp1_rwpf.c  --  R-Car VSP1 Read and Write Pixel Formatters4 *5 * Copyright (C) 2013-2014 Renesas Electronics Corporation6 *7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)8 */9 10#include <media/v4l2-subdev.h>11 12#include "vsp1.h"13#include "vsp1_rwpf.h"14#include "vsp1_video.h"15 16#define RWPF_MIN_WIDTH				117#define RWPF_MIN_HEIGHT				118 19/* -----------------------------------------------------------------------------20 * V4L2 Subdevice Operations21 */22 23static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,24				    struct v4l2_subdev_state *sd_state,25				    struct v4l2_subdev_mbus_code_enum *code)26{27	static const unsigned int codes[] = {28		MEDIA_BUS_FMT_ARGB8888_1X32,29		MEDIA_BUS_FMT_AHSV8888_1X32,30		MEDIA_BUS_FMT_AYUV8_1X32,31	};32 33	if (code->index >= ARRAY_SIZE(codes))34		return -EINVAL;35 36	code->code = codes[code->index];37 38	return 0;39}40 41static int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,42				     struct v4l2_subdev_state *sd_state,43				     struct v4l2_subdev_frame_size_enum *fse)44{45	struct vsp1_rwpf *rwpf = to_rwpf(subdev);46 47	return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,48					   RWPF_MIN_WIDTH,49					   RWPF_MIN_HEIGHT, rwpf->max_width,50					   rwpf->max_height);51}52 53static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,54				struct v4l2_subdev_state *sd_state,55				struct v4l2_subdev_format *fmt)56{57	struct vsp1_rwpf *rwpf = to_rwpf(subdev);58	struct v4l2_subdev_state *state;59	struct v4l2_mbus_framefmt *format;60	int ret = 0;61 62	mutex_lock(&rwpf->entity.lock);63 64	state = vsp1_entity_get_state(&rwpf->entity, sd_state, fmt->which);65	if (!state) {66		ret = -EINVAL;67		goto done;68	}69 70	/* Default to YUV if the requested format is not supported. */71	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&72	    fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&73	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)74		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;75 76	format = v4l2_subdev_state_get_format(state, fmt->pad);77 78	if (fmt->pad == RWPF_PAD_SOURCE) {79		/*80		 * The RWPF performs format conversion but can't scale, only the81		 * format code can be changed on the source pad.82		 */83		format->code = fmt->format.code;84		fmt->format = *format;85		goto done;86	}87 88	format->code = fmt->format.code;89	format->width = clamp_t(unsigned int, fmt->format.width,90				RWPF_MIN_WIDTH, rwpf->max_width);91	format->height = clamp_t(unsigned int, fmt->format.height,92				 RWPF_MIN_HEIGHT, rwpf->max_height);93	format->field = V4L2_FIELD_NONE;94	format->colorspace = V4L2_COLORSPACE_SRGB;95 96	fmt->format = *format;97 98	if (rwpf->entity.type == VSP1_ENTITY_RPF) {99		struct v4l2_rect *crop;100 101		/* Update the sink crop rectangle. */102		crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);103		crop->left = 0;104		crop->top = 0;105		crop->width = fmt->format.width;106		crop->height = fmt->format.height;107	}108 109	/* Propagate the format to the source pad. */110	format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);111	*format = fmt->format;112 113	if (rwpf->flip.rotate) {114		format->width = fmt->format.height;115		format->height = fmt->format.width;116	}117 118done:119	mutex_unlock(&rwpf->entity.lock);120	return ret;121}122 123static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,124				   struct v4l2_subdev_state *sd_state,125				   struct v4l2_subdev_selection *sel)126{127	struct vsp1_rwpf *rwpf = to_rwpf(subdev);128	struct v4l2_subdev_state *state;129	struct v4l2_mbus_framefmt *format;130	int ret = 0;131 132	/*133	 * Cropping is only supported on the RPF and is implemented on the sink134	 * pad.135	 */136	if (rwpf->entity.type == VSP1_ENTITY_WPF || sel->pad != RWPF_PAD_SINK)137		return -EINVAL;138 139	mutex_lock(&rwpf->entity.lock);140 141	state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which);142	if (!state) {143		ret = -EINVAL;144		goto done;145	}146 147	switch (sel->target) {148	case V4L2_SEL_TGT_CROP:149		sel->r = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);150		break;151 152	case V4L2_SEL_TGT_CROP_BOUNDS:153		format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);154		sel->r.left = 0;155		sel->r.top = 0;156		sel->r.width = format->width;157		sel->r.height = format->height;158		break;159 160	default:161		ret = -EINVAL;162		break;163	}164 165done:166	mutex_unlock(&rwpf->entity.lock);167	return ret;168}169 170static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,171				   struct v4l2_subdev_state *sd_state,172				   struct v4l2_subdev_selection *sel)173{174	struct vsp1_rwpf *rwpf = to_rwpf(subdev);175	struct v4l2_subdev_state *state;176	struct v4l2_mbus_framefmt *format;177	struct v4l2_rect *crop;178	int ret = 0;179 180	/*181	 * Cropping is only supported on the RPF and is implemented on the sink182	 * pad.183	 */184	if (rwpf->entity.type == VSP1_ENTITY_WPF || sel->pad != RWPF_PAD_SINK)185		return -EINVAL;186 187	if (sel->target != V4L2_SEL_TGT_CROP)188		return -EINVAL;189 190	mutex_lock(&rwpf->entity.lock);191 192	state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which);193	if (!state) {194		ret = -EINVAL;195		goto done;196	}197 198	/* Make sure the crop rectangle is entirely contained in the image. */199	format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);200 201	/*202	 * Restrict the crop rectangle coordinates to multiples of 2 to avoid203	 * shifting the color plane.204	 */205	if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) {206		sel->r.left = ALIGN(sel->r.left, 2);207		sel->r.top = ALIGN(sel->r.top, 2);208		sel->r.width = round_down(sel->r.width, 2);209		sel->r.height = round_down(sel->r.height, 2);210	}211 212	sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);213	sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);214	sel->r.width = min_t(unsigned int, sel->r.width,215			     format->width - sel->r.left);216	sel->r.height = min_t(unsigned int, sel->r.height,217			      format->height - sel->r.top);218 219	crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);220	*crop = sel->r;221 222	/* Propagate the format to the source pad. */223	format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);224	format->width = crop->width;225	format->height = crop->height;226 227done:228	mutex_unlock(&rwpf->entity.lock);229	return ret;230}231 232static const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {233	.enum_mbus_code = vsp1_rwpf_enum_mbus_code,234	.enum_frame_size = vsp1_rwpf_enum_frame_size,235	.get_fmt = vsp1_subdev_get_pad_format,236	.set_fmt = vsp1_rwpf_set_format,237	.get_selection = vsp1_rwpf_get_selection,238	.set_selection = vsp1_rwpf_set_selection,239};240 241const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops = {242	.pad    = &vsp1_rwpf_pad_ops,243};244 245/* -----------------------------------------------------------------------------246 * Controls247 */248 249static int vsp1_rwpf_s_ctrl(struct v4l2_ctrl *ctrl)250{251	struct vsp1_rwpf *rwpf =252		container_of(ctrl->handler, struct vsp1_rwpf, ctrls);253 254	switch (ctrl->id) {255	case V4L2_CID_ALPHA_COMPONENT:256		rwpf->alpha = ctrl->val;257		break;258	}259 260	return 0;261}262 263static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = {264	.s_ctrl = vsp1_rwpf_s_ctrl,265};266 267int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols)268{269	v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1);270	v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops,271			  V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);272 273	rwpf->entity.subdev.ctrl_handler = &rwpf->ctrls;274 275	return rwpf->ctrls.error;276}277