vsp1_entity.c 6.6 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

	if (!streaming)
		return 0;

48
	if (!entity->vsp1->pdata.uapi || !entity->subdev.ctrl_handler)
49 50 51 52
		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 67 68 69 70 71 72
void vsp1_entity_route_setup(struct vsp1_entity *source)
{
	struct vsp1_entity *sink;

	if (source->route->reg == 0)
		return;

	sink = container_of(source->sink, struct vsp1_entity, subdev.entity);
	vsp1_write(source->vsp1, source->route->reg,
		   sink->route->inputs[source->sink_pad]);
}

73 74 75 76 77 78
/* -----------------------------------------------------------------------------
 * V4L2 Subdevice Operations
 */

struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
79
			   struct v4l2_subdev_pad_config *cfg,
80 81 82 83
			   unsigned int pad, u32 which)
{
	switch (which) {
	case V4L2_SUBDEV_FORMAT_TRY:
84
		return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad);
85 86 87 88 89 90 91 92 93 94
	case V4L2_SUBDEV_FORMAT_ACTIVE:
		return &entity->formats[pad];
	default:
		return NULL;
	}
}

/*
 * vsp1_entity_init_formats - Initialize formats on all pads
 * @subdev: V4L2 subdevice
95
 * @cfg: V4L2 subdev pad configuration
96
 *
97
 * Initialize all pad formats with default values. If cfg is not NULL, try
98 99 100 101
 * formats are initialized on the file handle. Otherwise active formats are
 * initialized on the device.
 */
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
102
			    struct v4l2_subdev_pad_config *cfg)
103 104 105 106 107 108 109 110
{
	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;
111
		format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY
112 113
			     : V4L2_SUBDEV_FORMAT_ACTIVE;

114
		v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format);
115 116 117 118 119 120
	}
}

static int vsp1_entity_open(struct v4l2_subdev *subdev,
			    struct v4l2_subdev_fh *fh)
{
121
	vsp1_entity_init_formats(subdev, fh->pad);
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

	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;
152
		source->sink_pad = remote->index;
153 154
	} else {
		source->sink = NULL;
155
		source->sink_pad = 0;
156 157 158 159 160 161 162 163 164 165 166 167 168 169
	}

	return 0;
}

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

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

170
static const struct vsp1_route vsp1_routes[] = {
171 172 173
	{ 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), } },
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	{ 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), } },
};

193 194 195 196 197
int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
		     unsigned int num_pads)
{
	unsigned int i;

198 199 200 201
	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];
202 203 204 205
			break;
		}
	}

206
	if (i == ARRAY_SIZE(vsp1_routes))
207 208
		return -EINVAL;

209
	spin_lock_init(&entity->lock);
210

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
	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. */
233
	return media_entity_pads_init(&entity->subdev.entity, num_pads,
234
				 entity->pads);
235 236 237 238
}

void vsp1_entity_destroy(struct vsp1_entity *entity)
{
239 240
	if (entity->subdev.ctrl_handler)
		v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
241 242
	media_entity_cleanup(&entity->subdev.entity);
}