vsp1_entity.c 6.3 KB
Newer Older
1 2 3
/*
 * vsp1_entity.c  --  R-Car VSP1 Base Entity
 *
4
 * Copyright (C) 2013-2014 Renesas Electronics Corporation
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/device.h>
#include <linux/gfp.h>

#include <media/media-entity.h>
18
#include <media/v4l2-ctrls.h>
19 20 21 22 23
#include <media/v4l2-subdev.h>

#include "vsp1.h"
#include "vsp1_entity.h"

24 25
bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
{
26
	unsigned long flags;
27 28
	bool streaming;

29
	spin_lock_irqsave(&entity->lock, flags);
30
	streaming = entity->streaming;
31
	spin_unlock_irqrestore(&entity->lock, flags);
32 33 34 35 36 37

	return streaming;
}

int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
{
38
	unsigned long flags;
39 40
	int ret;

41
	spin_lock_irqsave(&entity->lock, flags);
42
	entity->streaming = streaming;
43
	spin_unlock_irqrestore(&entity->lock, flags);
44 45 46 47 48 49 50 51 52

	if (!streaming)
		return 0;

	if (!entity->subdev.ctrl_handler)
		return 0;

	ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler);
	if (ret < 0) {
53
		spin_lock_irqsave(&entity->lock, flags);
54
		entity->streaming = false;
55
		spin_unlock_irqrestore(&entity->lock, flags);
56 57 58 59 60
	}

	return ret;
}

61 62 63 64 65 66
/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Operations
 */

struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
67
			   struct v4l2_subdev_pad_config *cfg,
68 69 70 71
			   unsigned int pad, u32 which)
{
	switch (which) {
	case V4L2_SUBDEV_FORMAT_TRY:
72
		return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
73 74 75 76 77 78 79 80 81 82
	case V4L2_SUBDEV_FORMAT_ACTIVE:
		return &entity->formats[pad];
	default:
		return NULL;
	}
}

/*
 * vsp1_entity_init_formats - Initialize formats on all pads
 * @subdev: V4L2 subdevice
83
 * @cfg: V4L2 subdev pad configuration
84
 *
85
 * Initialize all pad formats with default values. If cfg is not NULL, try
86 87 88 89
 * formats are initialized on the file handle. Otherwise active formats are
 * initialized on the device.
 */
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
90
			    struct v4l2_subdev_pad_config *cfg)
91 92 93 94 95 96 97 98
{
	struct v4l2_subdev_format format;
	unsigned int pad;

	for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
		memset(&format, 0, sizeof(format));

		format.pad = pad;
99
		format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
100 101
			     : V4L2_SUBDEV_FORMAT_ACTIVE;

102
		v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
103 104 105 106 107 108
	}
}

static int vsp1_entity_open(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_fh *fh)
{
109
	vsp1_entity_init_formats(subdev, fh->pad);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

	return 0;
}

const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops = {
	.open = vsp1_entity_open,
};

/* -----------------------------------------------------------------------------
 * Media Operations
 */

static int vsp1_entity_link_setup(struct media_entity *entity,
				  const struct media_pad *local,
				  const struct media_pad *remote, u32 flags)
{
	struct vsp1_entity *source;

	if (!(local->flags & MEDIA_PAD_FL_SOURCE))
		return 0;

	source = container_of(local->entity, struct vsp1_entity, subdev.entity);

	if (!source->route)
		return 0;

	if (flags & MEDIA_LNK_FL_ENABLED) {
		if (source->sink)
			return -EBUSY;
		source->sink = remote->entity;
140
		source->sink_pad = remote->index;
141 142
	} else {
		source->sink = NULL;
143
		source->sink_pad = 0;
144 145 146 147 148 149 150 151 152 153 154 155 156 157
	}

	return 0;
}

const struct media_entity_operations vsp1_media_ops = {
	.link_setup = vsp1_entity_link_setup,
	.link_validate = v4l2_subdev_link_validate,
};

/* -----------------------------------------------------------------------------
 * Initialization
 */

158
static const struct vsp1_route vsp1_routes[] = {
159 160 161
	{ VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE,
	  { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1),
	    VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), } },
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
	{ VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } },
	{ VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } },
	{ VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } },
	{ VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } },
	{ VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } },
	{ VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } },
	{ VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } },
	{ VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } },
	{ VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } },
	{ VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } },
	{ VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } },
	{ VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } },
	{ VSP1_ENTITY_UDS, 2, VI6_DPR_UDS_ROUTE(2), { VI6_DPR_NODE_UDS(2), } },
	{ VSP1_ENTITY_WPF, 0, 0, { VI6_DPR_NODE_WPF(0), } },
	{ VSP1_ENTITY_WPF, 1, 0, { VI6_DPR_NODE_WPF(1), } },
	{ VSP1_ENTITY_WPF, 2, 0, { VI6_DPR_NODE_WPF(2), } },
	{ VSP1_ENTITY_WPF, 3, 0, { VI6_DPR_NODE_WPF(3), } },
};

181 182 183 184 185
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
		     unsigned int num_pads)
{
	unsigned int i;

186 187 188 189
	for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) {
		if (vsp1_routes[i].type == entity->type &&
		    vsp1_routes[i].index == entity->index) {
			entity->route = &vsp1_routes[i];
190 191 192 193
			break;
		}
	}

194
	if (i == ARRAY_SIZE(vsp1_routes))
195 196
		return -EINVAL;

197
	spin_lock_init(&entity->lock);
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	entity->vsp1 = vsp1;
	entity->source_pad = num_pads - 1;

	/* Allocate formats and pads. */
	entity->formats = devm_kzalloc(vsp1->dev,
				       num_pads * sizeof(*entity->formats),
				       GFP_KERNEL);
	if (entity->formats == NULL)
		return -ENOMEM;

	entity->pads = devm_kzalloc(vsp1->dev, num_pads * sizeof(*entity->pads),
				    GFP_KERNEL);
	if (entity->pads == NULL)
		return -ENOMEM;

	/* Initialize pads. */
	for (i = 0; i < num_pads - 1; ++i)
		entity->pads[i].flags = MEDIA_PAD_FL_SINK;

	entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE;

	/* Initialize the media entity. */
221
	return media_entity_pads_init(&entity->subdev.entity, num_pads,
222
				 entity->pads);
223 224 225 226
}

void vsp1_entity_destroy(struct vsp1_entity *entity)
{
227 228
	if (entity->subdev.ctrl_handler)
		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
229 230
	media_entity_cleanup(&entity->subdev.entity);
}