rcar-core.c 12.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Driver for Renesas R-Car VIN
 *
 * Copyright (C) 2016 Renesas Electronics Corp.
 * Copyright (C) 2011-2013 Renesas Solutions Corp.
 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
 * Copyright (C) 2008 Magnus Damm
 *
 * Based on the soc-camera rcar_vin driver
 *
 * 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/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
23
#include <linux/slab.h>
24

25
#include <media/v4l2-async.h>
26
#include <media/v4l2-fwnode.h>
27 28 29

#include "rcar-vin.h"

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
/* -----------------------------------------------------------------------------
 * Gen3 CSI2 Group Allocator
 */

/* FIXME:  This should if we find a system that supports more
 * than one group for the whole system be replaced with a linked
 * list of groups. And eventually all of this should be replaced
 * with a global device allocator API.
 *
 * But for now this works as on all supported systems there will
 * be only one group for all instances.
 */

static DEFINE_MUTEX(rvin_group_lock);
static struct rvin_group *rvin_group_data;

static void rvin_group_cleanup(struct rvin_group *group)
{
	media_device_unregister(&group->mdev);
	media_device_cleanup(&group->mdev);
	mutex_destroy(&group->lock);
}

static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin)
{
	struct media_device *mdev = &group->mdev;
	const struct of_device_id *match;
	struct device_node *np;
	int ret;

	mutex_init(&group->lock);

	/* Count number of VINs in the system */
	group->count = 0;
	for_each_matching_node(np, vin->dev->driver->of_match_table)
		if (of_device_is_available(np))
			group->count++;

	vin_dbg(vin, "found %u enabled VIN's in DT", group->count);

	mdev->dev = vin->dev;

	match = of_match_node(vin->dev->driver->of_match_table,
			      vin->dev->of_node);

	strlcpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name));
	strlcpy(mdev->model, match->compatible, sizeof(mdev->model));
	snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
		 dev_name(mdev->dev));

	media_device_init(mdev);

	ret = media_device_register(&group->mdev);
	if (ret)
		rvin_group_cleanup(group);

	return ret;
}

static void rvin_group_release(struct kref *kref)
{
	struct rvin_group *group =
		container_of(kref, struct rvin_group, refcount);

	mutex_lock(&rvin_group_lock);

	rvin_group_data = NULL;

	rvin_group_cleanup(group);

	kfree(group);

	mutex_unlock(&rvin_group_lock);
}

static int rvin_group_get(struct rvin_dev *vin)
{
	struct rvin_group *group;
	u32 id;
	int ret;

	/* Make sure VIN id is present and sane */
	ret = of_property_read_u32(vin->dev->of_node, "renesas,id", &id);
	if (ret) {
		vin_err(vin, "%pOF: No renesas,id property found\n",
			vin->dev->of_node);
		return -EINVAL;
	}

	if (id >= RCAR_VIN_NUM) {
		vin_err(vin, "%pOF: Invalid renesas,id '%u'\n",
			vin->dev->of_node, id);
		return -EINVAL;
	}

	/* Join or create a VIN group */
	mutex_lock(&rvin_group_lock);
	if (rvin_group_data) {
		group = rvin_group_data;
		kref_get(&group->refcount);
	} else {
		group = kzalloc(sizeof(*group), GFP_KERNEL);
		if (!group) {
			ret = -ENOMEM;
			goto err_group;
		}

		ret = rvin_group_init(group, vin);
		if (ret) {
			kfree(group);
			vin_err(vin, "Failed to initialize group\n");
			goto err_group;
		}

		kref_init(&group->refcount);

		rvin_group_data = group;
	}
	mutex_unlock(&rvin_group_lock);

	/* Add VIN to group */
	mutex_lock(&group->lock);

	if (group->vin[id]) {
		vin_err(vin, "Duplicate renesas,id property value %u\n", id);
		mutex_unlock(&group->lock);
		kref_put(&group->refcount, rvin_group_release);
		return -EINVAL;
	}

	group->vin[id] = vin;

	vin->id = id;
	vin->group = group;
	vin->v4l2_dev.mdev = &group->mdev;

	mutex_unlock(&group->lock);

	return 0;
err_group:
	mutex_unlock(&rvin_group_lock);
	return ret;
}

static void rvin_group_put(struct rvin_dev *vin)
{
	mutex_lock(&vin->group->lock);

	vin->group = NULL;
	vin->v4l2_dev.mdev = NULL;

	if (WARN_ON(vin->group->vin[vin->id] != vin))
		goto out;

	vin->group->vin[vin->id] = NULL;
out:
	mutex_unlock(&vin->group->lock);

	kref_put(&vin->group->refcount, rvin_group_release);
}

191 192 193 194 195 196
/* -----------------------------------------------------------------------------
 * Async notifier
 */

#define notifier_to_vin(n) container_of(n, struct rvin_dev, notifier)

197 198 199 200 201 202 203 204 205 206 207 208 209 210
static int rvin_find_pad(struct v4l2_subdev *sd, int direction)
{
	unsigned int pad;

	if (sd->entity.num_pads <= 1)
		return 0;

	for (pad = 0; pad < sd->entity.num_pads; pad++)
		if (sd->entity.pads[pad].flags & direction)
			return pad;

	return -EINVAL;
}

211 212 213 214
/* -----------------------------------------------------------------------------
 * Digital async notifier
 */

215 216 217
/* The vin lock should be held when calling the subdevice attach and detach */
static int rvin_digital_subdevice_attach(struct rvin_dev *vin,
					 struct v4l2_subdev *subdev)
218 219 220 221
{
	struct v4l2_subdev_mbus_code_enum code = {
		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
	};
222 223 224 225 226 227 228
	int ret;

	/* Find source and sink pad of remote subdevice */
	ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
	if (ret < 0)
		return ret;
	vin->digital->source_pad = ret;
229

230 231 232 233
	ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
	vin->digital->sink_pad = ret < 0 ? 0 : ret;

	/* Find compatible subdevices mbus format */
234
	vin->mbus_code = 0;
235
	code.index = 0;
236
	code.pad = vin->digital->source_pad;
237
	while (!vin->mbus_code &&
238
	       !v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) {
239 240 241
		code.index++;
		switch (code.code) {
		case MEDIA_BUS_FMT_YUYV8_1X16:
242 243
		case MEDIA_BUS_FMT_UYVY8_2X8:
		case MEDIA_BUS_FMT_UYVY10_2X10:
244
		case MEDIA_BUS_FMT_RGB888_1X24:
245
			vin->mbus_code = code.code;
246
			vin_dbg(vin, "Found media bus format for %s: %d\n",
247
				subdev->name, vin->mbus_code);
248
			break;
249 250 251 252 253
		default:
			break;
		}
	}

254
	if (!vin->mbus_code) {
255 256 257 258 259 260 261 262 263 264
		vin_err(vin, "Unsupported media bus format for %s\n",
			subdev->name);
		return -EINVAL;
	}

	/* Read tvnorms */
	ret = v4l2_subdev_call(subdev, video, g_tvnorms, &vin->vdev.tvnorms);
	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
		return ret;

265 266 267 268 269 270
	/* Read standard */
	vin->std = V4L2_STD_UNKNOWN;
	ret = v4l2_subdev_call(subdev, video, g_std, &vin->std);
	if (ret < 0 && ret != -ENOIOCTLCMD)
		return ret;

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
	/* Add the controls */
	ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16);
	if (ret < 0)
		return ret;

	ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler,
				    NULL);
	if (ret < 0) {
		v4l2_ctrl_handler_free(&vin->ctrl_handler);
		return ret;
	}

	vin->vdev.ctrl_handler = &vin->ctrl_handler;

	vin->digital->subdev = subdev;

	return 0;
}

static void rvin_digital_subdevice_detach(struct rvin_dev *vin)
{
	rvin_v4l2_unregister(vin);
	v4l2_ctrl_handler_free(&vin->ctrl_handler);

	vin->vdev.ctrl_handler = NULL;
	vin->digital->subdev = NULL;
297 298
}

299
static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)
300 301 302 303 304 305 306 307 308 309
{
	struct rvin_dev *vin = notifier_to_vin(notifier);
	int ret;

	ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
	if (ret < 0) {
		vin_err(vin, "Failed to register subdev nodes\n");
		return ret;
	}

310
	return rvin_v4l2_register(vin);
311 312
}

313 314 315
static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,
				       struct v4l2_subdev *subdev,
				       struct v4l2_async_subdev *asd)
316 317 318
{
	struct rvin_dev *vin = notifier_to_vin(notifier);

319
	vin_dbg(vin, "unbind digital subdev %s\n", subdev->name);
320 321 322 323

	mutex_lock(&vin->lock);
	rvin_digital_subdevice_detach(vin);
	mutex_unlock(&vin->lock);
324 325
}

326 327 328
static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
				     struct v4l2_subdev *subdev,
				     struct v4l2_async_subdev *asd)
329 330
{
	struct rvin_dev *vin = notifier_to_vin(notifier);
331
	int ret;
332

333 334 335 336
	mutex_lock(&vin->lock);
	ret = rvin_digital_subdevice_attach(vin, subdev);
	mutex_unlock(&vin->lock);
	if (ret)
337
		return ret;
338

339
	v4l2_set_subdev_hostdata(subdev, vin);
340

341
	vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
342 343
		subdev->name, vin->digital->source_pad,
		vin->digital->sink_pad);
344

345
	return 0;
346
}
347

348 349 350 351 352 353
static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = {
	.bound = rvin_digital_notify_bound,
	.unbind = rvin_digital_notify_unbind,
	.complete = rvin_digital_notify_complete,
};

354 355 356
static int rvin_digital_parse_v4l2(struct device *dev,
				   struct v4l2_fwnode_endpoint *vep,
				   struct v4l2_async_subdev *asd)
357
{
358 359 360
	struct rvin_dev *vin = dev_get_drvdata(dev);
	struct rvin_graph_entity *rvge =
		container_of(asd, struct rvin_graph_entity, asd);
361

362 363
	if (vep->base.port || vep->base.id)
		return -ENOTCONN;
364

365
	vin->mbus_cfg.type = vep->bus_type;
366

367
	switch (vin->mbus_cfg.type) {
368 369
	case V4L2_MBUS_PARALLEL:
		vin_dbg(vin, "Found PARALLEL media bus\n");
370
		vin->mbus_cfg.flags = vep->bus.parallel.flags;
371 372 373
		break;
	case V4L2_MBUS_BT656:
		vin_dbg(vin, "Found BT656 media bus\n");
374
		vin->mbus_cfg.flags = 0;
375 376 377 378 379
		break;
	default:
		vin_err(vin, "Unknown media bus type\n");
		return -EINVAL;
	}
380

381
	vin->digital = rvge;
382 383

	return 0;
384 385
}

386
static int rvin_digital_graph_init(struct rvin_dev *vin)
387 388 389
{
	int ret;

390 391 392
	ret = v4l2_async_notifier_parse_fwnode_endpoints(
		vin->dev, &vin->notifier,
		sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
393 394
	if (ret)
		return ret;
395

396
	if (!vin->digital)
397
		return -ENODEV;
398

399
	vin_dbg(vin, "Found digital subdevice %pOF\n",
400
		to_of_node(vin->digital->asd.match.fwnode));
401

402
	vin->notifier.ops = &rvin_digital_notify_ops;
403 404 405
	ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
	if (ret < 0) {
		vin_err(vin, "Notifier registration failed\n");
406
		return ret;
407 408
	}

409
	return 0;
410 411
}

412 413
static int rvin_mc_init(struct rvin_dev *vin)
{
414 415
	int ret;

416 417 418 419 420
	/* All our sources are CSI-2 */
	vin->mbus_cfg.type = V4L2_MBUS_CSI2;
	vin->mbus_cfg.flags = 0;

	vin->pad.flags = MEDIA_PAD_FL_SINK;
421 422 423 424 425
	ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad);
	if (ret)
		return ret;

	return rvin_group_get(vin);
426 427
}

428 429 430 431
/* -----------------------------------------------------------------------------
 * Platform Device Driver
 */

432 433
static const struct rvin_info rcar_info_h1 = {
	.model = RCAR_H1,
434
	.use_mc = false,
435 436
	.max_width = 2048,
	.max_height = 2048,
437 438 439 440
};

static const struct rvin_info rcar_info_m1 = {
	.model = RCAR_M1,
441
	.use_mc = false,
442 443
	.max_width = 2048,
	.max_height = 2048,
444 445 446 447
};

static const struct rvin_info rcar_info_gen2 = {
	.model = RCAR_GEN2,
448
	.use_mc = false,
449 450
	.max_width = 2048,
	.max_height = 2048,
451 452
};

453
static const struct of_device_id rvin_of_id_table[] = {
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
	{
		.compatible = "renesas,vin-r8a7778",
		.data = &rcar_info_m1,
	},
	{
		.compatible = "renesas,vin-r8a7779",
		.data = &rcar_info_h1,
	},
	{
		.compatible = "renesas,vin-r8a7790",
		.data = &rcar_info_gen2,
	},
	{
		.compatible = "renesas,vin-r8a7791",
		.data = &rcar_info_gen2,
	},
	{
		.compatible = "renesas,vin-r8a7793",
		.data = &rcar_info_gen2,
	},
	{
		.compatible = "renesas,vin-r8a7794",
		.data = &rcar_info_gen2,
	},
	{
		.compatible = "renesas,rcar-gen2-vin",
		.data = &rcar_info_gen2,
	},
	{ /* Sentinel */ },
483 484 485 486 487 488 489 490 491 492 493 494 495
};
MODULE_DEVICE_TABLE(of, rvin_of_id_table);

static int rcar_vin_probe(struct platform_device *pdev)
{
	struct rvin_dev *vin;
	struct resource *mem;
	int irq, ret;

	vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL);
	if (!vin)
		return -ENOMEM;

496
	vin->dev = &pdev->dev;
497
	vin->info = of_device_get_match_data(&pdev->dev);
498 499 500 501 502 503 504 505 506 507

	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (mem == NULL)
		return -EINVAL;

	vin->base = devm_ioremap_resource(vin->dev, mem);
	if (IS_ERR(vin->base))
		return PTR_ERR(vin->base);

	irq = platform_get_irq(pdev, 0);
508 509
	if (irq < 0)
		return irq;
510

511
	ret = rvin_dma_register(vin, irq);
512 513 514
	if (ret)
		return ret;

515
	platform_set_drvdata(pdev, vin);
516 517 518 519
	if (vin->info->use_mc)
		ret = rvin_mc_init(vin);
	else
		ret = rvin_digital_graph_init(vin);
520 521 522 523 524 525 526 527
	if (ret < 0)
		goto error;

	pm_suspend_ignore_children(&pdev->dev, true);
	pm_runtime_enable(&pdev->dev);

	return 0;
error:
528
	rvin_dma_unregister(vin);
529
	v4l2_async_notifier_cleanup(&vin->notifier);
530 531 532 533 534 535 536 537 538 539

	return ret;
}

static int rcar_vin_remove(struct platform_device *pdev)
{
	struct rvin_dev *vin = platform_get_drvdata(pdev);

	pm_runtime_disable(&pdev->dev);

540 541
	rvin_v4l2_unregister(vin);

542
	v4l2_async_notifier_unregister(&vin->notifier);
543
	v4l2_async_notifier_cleanup(&vin->notifier);
544

545 546 547
	if (vin->info->use_mc)
		rvin_group_put(vin);
	else
548
		v4l2_ctrl_handler_free(&vin->ctrl_handler);
549

550
	rvin_dma_unregister(vin);
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568

	return 0;
}

static struct platform_driver rcar_vin_driver = {
	.driver = {
		.name = "rcar-vin",
		.of_match_table = rvin_of_id_table,
	},
	.probe = rcar_vin_probe,
	.remove = rcar_vin_remove,
};

module_platform_driver(rcar_vin_driver);

MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
MODULE_LICENSE("GPL v2");