2 * vsp1_entity.c -- R-Car VSP1 Base Entity
4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
14 #include <linux/device.h>
15 #include <linux/gfp.h>
17 #include <media/media-entity.h>
18 #include <media/v4l2-ctrls.h>
19 #include <media/v4l2-subdev.h>
23 #include "vsp1_entity.h"
25 static inline struct vsp1_entity
*
26 media_entity_to_vsp1_entity(struct media_entity
*entity
)
28 return container_of(entity
, struct vsp1_entity
, subdev
.entity
);
31 void vsp1_entity_route_setup(struct vsp1_entity
*source
,
32 struct vsp1_dl_list
*dl
)
34 struct vsp1_entity
*sink
;
36 if (source
->route
->reg
== 0)
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
]);
44 /* -----------------------------------------------------------------------------
45 * V4L2 Subdevice Operations
49 * vsp1_entity_get_pad_config - Get the pad configuration for an entity
51 * @cfg: the TRY pad configuration
52 * @which: configuration selector (ACTIVE or TRY)
54 * Return the pad configuration requested by the which argument. The TRY
55 * configuration is passed explicitly to the function through the cfg argument
56 * and simply returned when requested. The ACTIVE configuration comes from the
59 struct v4l2_subdev_pad_config
*
60 vsp1_entity_get_pad_config(struct vsp1_entity
*entity
,
61 struct v4l2_subdev_pad_config
*cfg
,
62 enum v4l2_subdev_format_whence which
)
65 case V4L2_SUBDEV_FORMAT_ACTIVE
:
66 return entity
->config
;
67 case V4L2_SUBDEV_FORMAT_TRY
:
74 * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
76 * @cfg: the configuration storage
77 * @pad: the pad number
79 * Return the format stored in the given configuration for an entity's pad. The
80 * configuration can be an ACTIVE or TRY configuration.
82 struct v4l2_mbus_framefmt
*
83 vsp1_entity_get_pad_format(struct vsp1_entity
*entity
,
84 struct v4l2_subdev_pad_config
*cfg
,
87 return v4l2_subdev_get_try_format(&entity
->subdev
, cfg
, pad
);
91 * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
93 * @cfg: the configuration storage
94 * @pad: the pad number
95 * @target: the selection target
97 * Return the selection rectangle stored in the given configuration for an
98 * entity's pad. The configuration can be an ACTIVE or TRY configuration. The
99 * selection target can be COMPOSE or CROP.
102 vsp1_entity_get_pad_selection(struct vsp1_entity
*entity
,
103 struct v4l2_subdev_pad_config
*cfg
,
104 unsigned int pad
, unsigned int target
)
107 case V4L2_SEL_TGT_COMPOSE
:
108 return v4l2_subdev_get_try_compose(&entity
->subdev
, cfg
, pad
);
109 case V4L2_SEL_TGT_CROP
:
110 return v4l2_subdev_get_try_crop(&entity
->subdev
, cfg
, pad
);
117 * vsp1_entity_init_cfg - Initialize formats on all pads
118 * @subdev: V4L2 subdevice
119 * @cfg: V4L2 subdev pad configuration
121 * Initialize all pad formats with default values in the given pad config. This
122 * function can be used as a handler for the subdev pad::init_cfg operation.
124 int vsp1_entity_init_cfg(struct v4l2_subdev
*subdev
,
125 struct v4l2_subdev_pad_config
*cfg
)
127 struct v4l2_subdev_format format
;
130 for (pad
= 0; pad
< subdev
->entity
.num_pads
- 1; ++pad
) {
131 memset(&format
, 0, sizeof(format
));
134 format
.which
= cfg
? V4L2_SUBDEV_FORMAT_TRY
135 : V4L2_SUBDEV_FORMAT_ACTIVE
;
137 v4l2_subdev_call(subdev
, pad
, set_fmt
, cfg
, &format
);
144 * vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
145 * @subdev: V4L2 subdevice
146 * @cfg: V4L2 subdev pad configuration
147 * @fmt: V4L2 subdev format
149 * This function implements the subdev get_fmt pad operation. It can be used as
150 * a direct drop-in for the operation handler.
152 int vsp1_subdev_get_pad_format(struct v4l2_subdev
*subdev
,
153 struct v4l2_subdev_pad_config
*cfg
,
154 struct v4l2_subdev_format
*fmt
)
156 struct vsp1_entity
*entity
= to_vsp1_entity(subdev
);
157 struct v4l2_subdev_pad_config
*config
;
159 config
= vsp1_entity_get_pad_config(entity
, cfg
, fmt
->which
);
163 fmt
->format
= *vsp1_entity_get_pad_format(entity
, config
, fmt
->pad
);
169 * vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler
170 * @subdev: V4L2 subdevice
171 * @cfg: V4L2 subdev pad configuration
172 * @code: Media bus code enumeration
173 * @codes: Array of supported media bus codes
174 * @ncodes: Number of supported media bus codes
176 * This function implements the subdev enum_mbus_code pad operation for entities
177 * that do not support format conversion. It enumerates the given supported
178 * media bus codes on the sink pad and reports a source pad format identical to
181 int vsp1_subdev_enum_mbus_code(struct v4l2_subdev
*subdev
,
182 struct v4l2_subdev_pad_config
*cfg
,
183 struct v4l2_subdev_mbus_code_enum
*code
,
184 const unsigned int *codes
, unsigned int ncodes
)
186 struct vsp1_entity
*entity
= to_vsp1_entity(subdev
);
188 if (code
->pad
== 0) {
189 if (code
->index
>= ncodes
)
192 code
->code
= codes
[code
->index
];
194 struct v4l2_subdev_pad_config
*config
;
195 struct v4l2_mbus_framefmt
*format
;
197 /* The entity can't perform format conversion, the sink format
198 * is always identical to the source format.
203 config
= vsp1_entity_get_pad_config(entity
, cfg
, code
->which
);
207 format
= vsp1_entity_get_pad_format(entity
, config
, 0);
208 code
->code
= format
->code
;
215 * vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler
216 * @subdev: V4L2 subdevice
217 * @cfg: V4L2 subdev pad configuration
218 * @fse: Frame size enumeration
219 * @min_width: Minimum image width
220 * @min_height: Minimum image height
221 * @max_width: Maximum image width
222 * @max_height: Maximum image height
224 * This function implements the subdev enum_frame_size pad operation for
225 * entities that do not support scaling or cropping. It reports the given
226 * minimum and maximum frame width and height on the sink pad, and a fixed
227 * source pad size identical to the sink pad.
229 int vsp1_subdev_enum_frame_size(struct v4l2_subdev
*subdev
,
230 struct v4l2_subdev_pad_config
*cfg
,
231 struct v4l2_subdev_frame_size_enum
*fse
,
232 unsigned int min_width
, unsigned int min_height
,
233 unsigned int max_width
, unsigned int max_height
)
235 struct vsp1_entity
*entity
= to_vsp1_entity(subdev
);
236 struct v4l2_subdev_pad_config
*config
;
237 struct v4l2_mbus_framefmt
*format
;
239 config
= vsp1_entity_get_pad_config(entity
, cfg
, fse
->which
);
243 format
= vsp1_entity_get_pad_format(entity
, config
, fse
->pad
);
245 if (fse
->index
|| fse
->code
!= format
->code
)
249 fse
->min_width
= min_width
;
250 fse
->max_width
= max_width
;
251 fse
->min_height
= min_height
;
252 fse
->max_height
= max_height
;
254 /* The size on the source pad are fixed and always identical to
255 * the size on the sink pad.
257 fse
->min_width
= format
->width
;
258 fse
->max_width
= format
->width
;
259 fse
->min_height
= format
->height
;
260 fse
->max_height
= format
->height
;
266 /* -----------------------------------------------------------------------------
270 int vsp1_entity_link_setup(struct media_entity
*entity
,
271 const struct media_pad
*local
,
272 const struct media_pad
*remote
, u32 flags
)
274 struct vsp1_entity
*source
;
276 if (!(local
->flags
& MEDIA_PAD_FL_SOURCE
))
279 source
= media_entity_to_vsp1_entity(local
->entity
);
284 if (flags
& MEDIA_LNK_FL_ENABLED
) {
287 source
->sink
= remote
->entity
;
288 source
->sink_pad
= remote
->index
;
291 source
->sink_pad
= 0;
297 /* -----------------------------------------------------------------------------
301 #define VSP1_ENTITY_ROUTE(ent) \
302 { VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE, \
303 { VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent }
305 #define VSP1_ENTITY_ROUTE_RPF(idx) \
306 { VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx), \
307 { 0, }, VI6_DPR_NODE_RPF(idx) }
309 #define VSP1_ENTITY_ROUTE_UDS(idx) \
310 { VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx), \
311 { VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) }
313 #define VSP1_ENTITY_ROUTE_WPF(idx) \
314 { VSP1_ENTITY_WPF, idx, 0, \
315 { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) }
317 static const struct vsp1_route vsp1_routes
[] = {
318 { VSP1_ENTITY_BRU
, 0, VI6_DPR_BRU_ROUTE
,
319 { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
320 VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3),
321 VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT
},
322 VSP1_ENTITY_ROUTE(CLU
),
323 VSP1_ENTITY_ROUTE(HSI
),
324 VSP1_ENTITY_ROUTE(HST
),
325 { VSP1_ENTITY_LIF
, 0, 0, { VI6_DPR_NODE_LIF
, }, VI6_DPR_NODE_LIF
},
326 VSP1_ENTITY_ROUTE(LUT
),
327 VSP1_ENTITY_ROUTE_RPF(0),
328 VSP1_ENTITY_ROUTE_RPF(1),
329 VSP1_ENTITY_ROUTE_RPF(2),
330 VSP1_ENTITY_ROUTE_RPF(3),
331 VSP1_ENTITY_ROUTE_RPF(4),
332 VSP1_ENTITY_ROUTE(SRU
),
333 VSP1_ENTITY_ROUTE_UDS(0),
334 VSP1_ENTITY_ROUTE_UDS(1),
335 VSP1_ENTITY_ROUTE_UDS(2),
336 VSP1_ENTITY_ROUTE_WPF(0),
337 VSP1_ENTITY_ROUTE_WPF(1),
338 VSP1_ENTITY_ROUTE_WPF(2),
339 VSP1_ENTITY_ROUTE_WPF(3),
342 int vsp1_entity_init(struct vsp1_device
*vsp1
, struct vsp1_entity
*entity
,
343 const char *name
, unsigned int num_pads
,
344 const struct v4l2_subdev_ops
*ops
, u32 function
)
346 struct v4l2_subdev
*subdev
;
350 for (i
= 0; i
< ARRAY_SIZE(vsp1_routes
); ++i
) {
351 if (vsp1_routes
[i
].type
== entity
->type
&&
352 vsp1_routes
[i
].index
== entity
->index
) {
353 entity
->route
= &vsp1_routes
[i
];
358 if (i
== ARRAY_SIZE(vsp1_routes
))
362 entity
->source_pad
= num_pads
- 1;
364 /* Allocate and initialize pads. */
365 entity
->pads
= devm_kzalloc(vsp1
->dev
, num_pads
* sizeof(*entity
->pads
),
367 if (entity
->pads
== NULL
)
370 for (i
= 0; i
< num_pads
- 1; ++i
)
371 entity
->pads
[i
].flags
= MEDIA_PAD_FL_SINK
;
373 entity
->pads
[num_pads
- 1].flags
= MEDIA_PAD_FL_SOURCE
;
375 /* Initialize the media entity. */
376 ret
= media_entity_pads_init(&entity
->subdev
.entity
, num_pads
,
381 /* Initialize the V4L2 subdev. */
382 subdev
= &entity
->subdev
;
383 v4l2_subdev_init(subdev
, ops
);
385 subdev
->entity
.function
= function
;
386 subdev
->entity
.ops
= &vsp1
->media_ops
;
387 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
389 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s %s",
390 dev_name(vsp1
->dev
), name
);
392 vsp1_entity_init_cfg(subdev
, NULL
);
394 /* Allocate the pad configuration to store formats and selection
397 entity
->config
= v4l2_subdev_alloc_pad_config(&entity
->subdev
);
398 if (entity
->config
== NULL
) {
399 media_entity_cleanup(&entity
->subdev
.entity
);
406 void vsp1_entity_destroy(struct vsp1_entity
*entity
)
408 if (entity
->ops
&& entity
->ops
->destroy
)
409 entity
->ops
->destroy(entity
);
410 if (entity
->subdev
.ctrl_handler
)
411 v4l2_ctrl_handler_free(entity
->subdev
.ctrl_handler
);
412 v4l2_subdev_free_pad_config(entity
->config
);
413 media_entity_cleanup(&entity
->subdev
.entity
);