• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * vsp1_entity.c  --  R-Car VSP1 Base Entity
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 <linux/device.h>
15 #include <linux/gfp.h>
16 
17 #include <media/media-entity.h>
18 #include <media/v4l2-ctrls.h>
19 #include <media/v4l2-subdev.h>
20 
21 #include "vsp1.h"
22 #include "vsp1_dl.h"
23 #include "vsp1_entity.h"
24 
25 static inline struct vsp1_entity *
media_entity_to_vsp1_entity(struct media_entity * entity)26 media_entity_to_vsp1_entity(struct media_entity *entity)
27 {
28 	return container_of(entity, struct vsp1_entity, subdev.entity);
29 }
30 
vsp1_entity_route_setup(struct vsp1_entity * source,struct vsp1_dl_list * dl)31 void vsp1_entity_route_setup(struct vsp1_entity *source,
32 			     struct vsp1_dl_list *dl)
33 {
34 	struct vsp1_entity *sink;
35 
36 	if (source->route->reg == 0)
37 		return;
38 
39 	sink = media_entity_to_vsp1_entity(source->sink);
40 	vsp1_dl_list_write(dl, source->route->reg,
41 			   sink->route->inputs[source->sink_pad]);
42 }
43 
44 /* -----------------------------------------------------------------------------
45  * V4L2 Subdevice Operations
46  */
47 
48 /**
49  * vsp1_entity_get_pad_config - Get the pad configuration for an entity
50  * @entity: the entity
51  * @cfg: the TRY pad configuration
52  * @which: configuration selector (ACTIVE or TRY)
53  *
54  * When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold
55  * the entity lock to access the returned configuration.
56  *
57  * Return the pad configuration requested by the which argument. The TRY
58  * configuration is passed explicitly to the function through the cfg argument
59  * and simply returned when requested. The ACTIVE configuration comes from the
60  * entity structure.
61  */
62 struct v4l2_subdev_pad_config *
vsp1_entity_get_pad_config(struct vsp1_entity * entity,struct v4l2_subdev_pad_config * cfg,enum v4l2_subdev_format_whence which)63 vsp1_entity_get_pad_config(struct vsp1_entity *entity,
64 			   struct v4l2_subdev_pad_config *cfg,
65 			   enum v4l2_subdev_format_whence which)
66 {
67 	switch (which) {
68 	case V4L2_SUBDEV_FORMAT_ACTIVE:
69 		return entity->config;
70 	case V4L2_SUBDEV_FORMAT_TRY:
71 	default:
72 		return cfg;
73 	}
74 }
75 
76 /**
77  * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
78  * @entity: the entity
79  * @cfg: the configuration storage
80  * @pad: the pad number
81  *
82  * Return the format stored in the given configuration for an entity's pad. The
83  * configuration can be an ACTIVE or TRY configuration.
84  */
85 struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity * entity,struct v4l2_subdev_pad_config * cfg,unsigned int pad)86 vsp1_entity_get_pad_format(struct vsp1_entity *entity,
87 			   struct v4l2_subdev_pad_config *cfg,
88 			   unsigned int pad)
89 {
90 	return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
91 }
92 
93 /**
94  * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
95  * @entity: the entity
96  * @cfg: the configuration storage
97  * @pad: the pad number
98  * @target: the selection target
99  *
100  * Return the selection rectangle stored in the given configuration for an
101  * entity's pad. The configuration can be an ACTIVE or TRY configuration. The
102  * selection target can be COMPOSE or CROP.
103  */
104 struct v4l2_rect *
vsp1_entity_get_pad_selection(struct vsp1_entity * entity,struct v4l2_subdev_pad_config * cfg,unsigned int pad,unsigned int target)105 vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
106 			      struct v4l2_subdev_pad_config *cfg,
107 			      unsigned int pad, unsigned int target)
108 {
109 	switch (target) {
110 	case V4L2_SEL_TGT_COMPOSE:
111 		return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad);
112 	case V4L2_SEL_TGT_CROP:
113 		return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad);
114 	default:
115 		return NULL;
116 	}
117 }
118 
119 /*
120  * vsp1_entity_init_cfg - Initialize formats on all pads
121  * @subdev: V4L2 subdevice
122  * @cfg: V4L2 subdev pad configuration
123  *
124  * Initialize all pad formats with default values in the given pad config. This
125  * function can be used as a handler for the subdev pad::init_cfg operation.
126  */
vsp1_entity_init_cfg(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg)127 int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
128 			 struct v4l2_subdev_pad_config *cfg)
129 {
130 	struct v4l2_subdev_format format;
131 	unsigned int pad;
132 
133 	for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
134 		memset(&format, 0, sizeof(format));
135 
136 		format.pad = pad;
137 		format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
138 			     : V4L2_SUBDEV_FORMAT_ACTIVE;
139 
140 		v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
141 	}
142 
143 	return 0;
144 }
145 
146 /*
147  * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
148  * @subdev: V4L2 subdevice
149  * @cfg: V4L2 subdev pad configuration
150  * @fmt: V4L2 subdev format
151  *
152  * This function implements the subdev get_fmt pad operation. It can be used as
153  * a direct drop-in for the operation handler.
154  */
vsp1_subdev_get_pad_format(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)155 int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
156 			       struct v4l2_subdev_pad_config *cfg,
157 			       struct v4l2_subdev_format *fmt)
158 {
159 	struct vsp1_entity *entity = to_vsp1_entity(subdev);
160 	struct v4l2_subdev_pad_config *config;
161 
162 	config = vsp1_entity_get_pad_config(entity, cfg, fmt->which);
163 	if (!config)
164 		return -EINVAL;
165 
166 	mutex_lock(&entity->lock);
167 	fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad);
168 	mutex_unlock(&entity->lock);
169 
170 	return 0;
171 }
172 
173 /*
174  * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler
175  * @subdev: V4L2 subdevice
176  * @cfg: V4L2 subdev pad configuration
177  * @code: Media bus code enumeration
178  * @codes: Array of supported media bus codes
179  * @ncodes: Number of supported media bus codes
180  *
181  * This function implements the subdev enum_mbus_code pad operation for entities
182  * that do not support format conversion. It enumerates the given supported
183  * media bus codes on the sink pad and reports a source pad format identical to
184  * the sink pad.
185  */
vsp1_subdev_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code,const unsigned int * codes,unsigned int ncodes)186 int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
187 			       struct v4l2_subdev_pad_config *cfg,
188 			       struct v4l2_subdev_mbus_code_enum *code,
189 			       const unsigned int *codes, unsigned int ncodes)
190 {
191 	struct vsp1_entity *entity = to_vsp1_entity(subdev);
192 
193 	if (code->pad == 0) {
194 		if (code->index >= ncodes)
195 			return -EINVAL;
196 
197 		code->code = codes[code->index];
198 	} else {
199 		struct v4l2_subdev_pad_config *config;
200 		struct v4l2_mbus_framefmt *format;
201 
202 		/* The entity can't perform format conversion, the sink format
203 		 * is always identical to the source format.
204 		 */
205 		if (code->index)
206 			return -EINVAL;
207 
208 		config = vsp1_entity_get_pad_config(entity, cfg, code->which);
209 		if (!config)
210 			return -EINVAL;
211 
212 		mutex_lock(&entity->lock);
213 		format = vsp1_entity_get_pad_format(entity, config, 0);
214 		code->code = format->code;
215 		mutex_unlock(&entity->lock);
216 	}
217 
218 	return 0;
219 }
220 
221 /*
222  * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler
223  * @subdev: V4L2 subdevice
224  * @cfg: V4L2 subdev pad configuration
225  * @fse: Frame size enumeration
226  * @min_width: Minimum image width
227  * @min_height: Minimum image height
228  * @max_width: Maximum image width
229  * @max_height: Maximum image height
230  *
231  * This function implements the subdev enum_frame_size pad operation for
232  * entities that do not support scaling or cropping. It reports the given
233  * minimum and maximum frame width and height on the sink pad, and a fixed
234  * source pad size identical to the sink pad.
235  */
vsp1_subdev_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse,unsigned int min_width,unsigned int min_height,unsigned int max_width,unsigned int max_height)236 int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
237 				struct v4l2_subdev_pad_config *cfg,
238 				struct v4l2_subdev_frame_size_enum *fse,
239 				unsigned int min_width, unsigned int min_height,
240 				unsigned int max_width, unsigned int max_height)
241 {
242 	struct vsp1_entity *entity = to_vsp1_entity(subdev);
243 	struct v4l2_subdev_pad_config *config;
244 	struct v4l2_mbus_framefmt *format;
245 	int ret = 0;
246 
247 	config = vsp1_entity_get_pad_config(entity, cfg, fse->which);
248 	if (!config)
249 		return -EINVAL;
250 
251 	format = vsp1_entity_get_pad_format(entity, config, fse->pad);
252 
253 	mutex_lock(&entity->lock);
254 
255 	if (fse->index || fse->code != format->code) {
256 		ret = -EINVAL;
257 		goto done;
258 	}
259 
260 	if (fse->pad == 0) {
261 		fse->min_width = min_width;
262 		fse->max_width = max_width;
263 		fse->min_height = min_height;
264 		fse->max_height = max_height;
265 	} else {
266 		/* The size on the source pad are fixed and always identical to
267 		 * the size on the sink pad.
268 		 */
269 		fse->min_width = format->width;
270 		fse->max_width = format->width;
271 		fse->min_height = format->height;
272 		fse->max_height = format->height;
273 	}
274 
275 done:
276 	mutex_unlock(&entity->lock);
277 	return ret;
278 }
279 
280 /* -----------------------------------------------------------------------------
281  * Media Operations
282  */
283 
vsp1_entity_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)284 int vsp1_entity_link_setup(struct media_entity *entity,
285 			   const struct media_pad *local,
286 			   const struct media_pad *remote, u32 flags)
287 {
288 	struct vsp1_entity *source;
289 
290 	if (!(local->flags & MEDIA_PAD_FL_SOURCE))
291 		return 0;
292 
293 	source = media_entity_to_vsp1_entity(local->entity);
294 
295 	if (!source->route)
296 		return 0;
297 
298 	if (flags & MEDIA_LNK_FL_ENABLED) {
299 		if (source->sink)
300 			return -EBUSY;
301 		source->sink = remote->entity;
302 		source->sink_pad = remote->index;
303 	} else {
304 		source->sink = NULL;
305 		source->sink_pad = 0;
306 	}
307 
308 	return 0;
309 }
310 
311 /* -----------------------------------------------------------------------------
312  * Initialization
313  */
314 
315 #define VSP1_ENTITY_ROUTE(ent)						\
316 	{ VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE,			\
317 	  { VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent }
318 
319 #define VSP1_ENTITY_ROUTE_RPF(idx)					\
320 	{ VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx),			\
321 	  { 0, }, VI6_DPR_NODE_RPF(idx) }
322 
323 #define VSP1_ENTITY_ROUTE_UDS(idx)					\
324 	{ VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx),			\
325 	  { VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) }
326 
327 #define VSP1_ENTITY_ROUTE_WPF(idx)					\
328 	{ VSP1_ENTITY_WPF, idx, 0,					\
329 	  { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) }
330 
331 static const struct vsp1_route vsp1_routes[] = {
332 	{ VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE,
333 	  { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
334 	    VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3),
335 	    VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT },
336 	VSP1_ENTITY_ROUTE(CLU),
337 	VSP1_ENTITY_ROUTE(HSI),
338 	VSP1_ENTITY_ROUTE(HST),
339 	{ VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF },
340 	VSP1_ENTITY_ROUTE(LUT),
341 	VSP1_ENTITY_ROUTE_RPF(0),
342 	VSP1_ENTITY_ROUTE_RPF(1),
343 	VSP1_ENTITY_ROUTE_RPF(2),
344 	VSP1_ENTITY_ROUTE_RPF(3),
345 	VSP1_ENTITY_ROUTE_RPF(4),
346 	VSP1_ENTITY_ROUTE(SRU),
347 	VSP1_ENTITY_ROUTE_UDS(0),
348 	VSP1_ENTITY_ROUTE_UDS(1),
349 	VSP1_ENTITY_ROUTE_UDS(2),
350 	VSP1_ENTITY_ROUTE_WPF(0),
351 	VSP1_ENTITY_ROUTE_WPF(1),
352 	VSP1_ENTITY_ROUTE_WPF(2),
353 	VSP1_ENTITY_ROUTE_WPF(3),
354 };
355 
vsp1_entity_init(struct vsp1_device * vsp1,struct vsp1_entity * entity,const char * name,unsigned int num_pads,const struct v4l2_subdev_ops * ops,u32 function)356 int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
357 		     const char *name, unsigned int num_pads,
358 		     const struct v4l2_subdev_ops *ops, u32 function)
359 {
360 	struct v4l2_subdev *subdev;
361 	unsigned int i;
362 	int ret;
363 
364 	for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
365 		if (vsp1_routes[i].type == entity->type &&
366 		    vsp1_routes[i].index == entity->index) {
367 			entity->route = &vsp1_routes[i];
368 			break;
369 		}
370 	}
371 
372 	if (i == ARRAY_SIZE(vsp1_routes))
373 		return -EINVAL;
374 
375 	mutex_init(&entity->lock);
376 
377 	entity->vsp1 = vsp1;
378 	entity->source_pad = num_pads - 1;
379 
380 	/* Allocate and initialize pads. */
381 	entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
382 				    GFP_KERNEL);
383 	if (entity->pads == NULL)
384 		return -ENOMEM;
385 
386 	for (i = 0; i < num_pads - 1; ++i)
387 		entity->pads[i].flags = MEDIA_PAD_FL_SINK;
388 
389 	entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;
390 
391 	/* Initialize the media entity. */
392 	ret = media_entity_pads_init(&entity->subdev.entity, num_pads,
393 				     entity->pads);
394 	if (ret < 0)
395 		return ret;
396 
397 	/* Initialize the V4L2 subdev. */
398 	subdev = &entity->subdev;
399 	v4l2_subdev_init(subdev, ops);
400 
401 	subdev->entity.function = function;
402 	subdev->entity.ops = &vsp1->media_ops;
403 	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
404 
405 	snprintf(subdev->name, sizeof(subdev->name), "%s %s",
406 		 dev_name(vsp1->dev), name);
407 
408 	vsp1_entity_init_cfg(subdev, NULL);
409 
410 	/* Allocate the pad configuration to store formats and selection
411 	 * rectangles.
412 	 */
413 	entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev);
414 	if (entity->config == NULL) {
415 		media_entity_cleanup(&entity->subdev.entity);
416 		return -ENOMEM;
417 	}
418 
419 	return 0;
420 }
421 
vsp1_entity_destroy(struct vsp1_entity * entity)422 void vsp1_entity_destroy(struct vsp1_entity *entity)
423 {
424 	if (entity->ops && entity->ops->destroy)
425 		entity->ops->destroy(entity);
426 	if (entity->subdev.ctrl_handler)
427 		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
428 	v4l2_subdev_free_pad_config(entity->config);
429 	media_entity_cleanup(&entity->subdev.entity);
430 }
431