FILE
rcar-core.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/renesas/rcar-vin/rcar-core.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Driver for Renesas R-Car VIN 4 * 5 * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> 6 * Copyright (C) 2016 Renesas Electronics Corp. 7 * Copyright (C) 2011-2013 Renesas Solutions Corp. 8 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> 9 * Copyright (C) 2008 Magnus Damm 10 */ 11 12#include <linux/idr.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/of_graph.h> 16#include <linux/platform_device.h> 17#include <linux/pm_runtime.h> 18#include <linux/slab.h> 19 20#include <media/v4l2-async.h> 21#include <media/v4l2-fwnode.h> 22#include <media/v4l2-mc.h> 23 24#include "rcar-vin.h" 25 26/* 27 * The companion CSI-2 receiver driver (rcar-csi2) is known 28 * and we know it has one source pad (pad 0) and four sink 29 * pads (pad 1-4). So to translate a pad on the remote 30 * CSI-2 receiver to/from the VIN internal channel number simply 31 * subtract/add one from the pad/channel number. 32 */ 33#define rvin_group_csi_pad_to_channel(pad) ((pad) - 1) 34#define rvin_group_csi_channel_to_pad(channel) ((channel) + 1) 35 36/* 37 * Not all VINs are created equal, master VINs control the 38 * routing for other VIN's. We can figure out which VIN is 39 * master by looking at a VINs id. 40 */ 41#define rvin_group_id_to_master(vin) ((vin) < 4 ? 0 : 4) 42 43#define v4l2_dev_to_vin(d) container_of(d, struct rvin_dev, v4l2_dev) 44 45/* ----------------------------------------------------------------------------- 46 * Gen3 Group Allocator 47 */ 48 49/* FIXME: This should if we find a system that supports more 50 * than one group for the whole system be replaced with a linked 51 * list of groups. And eventually all of this should be replaced 52 * with a global device allocator API. 53 * 54 * But for now this works as on all supported systems there will 55 * be only one group for all instances. 56 */ 57 58static DEFINE_IDA(rvin_ida); 59static DEFINE_MUTEX(rvin_group_lock); 60static struct rvin_group *rvin_group_data; 61 62static void rvin_group_cleanup(struct rvin_group *group) 63{ 64 media_device_cleanup(&group->mdev); 65 mutex_destroy(&group->lock); 66} 67 68static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, 69 int (*link_setup)(struct rvin_group *), 70 const struct media_device_ops *ops) 71{ 72 struct media_device *mdev = &group->mdev; 73 const struct of_device_id *match; 74 struct device_node *np; 75 76 mutex_init(&group->lock); 77 78 /* Count number of VINs in the system */ 79 group->count = 0; 80 for_each_matching_node(np, vin->dev->driver->of_match_table) 81 if (of_device_is_available(np)) 82 group->count++; 83 84 vin_dbg(vin, "found %u enabled VIN's in DT", group->count); 85 86 group->link_setup = link_setup; 87 88 mdev->dev = vin->dev; 89 mdev->ops = ops; 90 91 match = of_match_node(vin->dev->driver->of_match_table, 92 vin->dev->of_node); 93 94 strscpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name)); 95 strscpy(mdev->model, match->compatible, sizeof(mdev->model)); 96 97 media_device_init(mdev); 98 99 return 0; 100} 101 102static void rvin_group_release(struct kref *kref) 103{ 104 struct rvin_group *group = 105 container_of(kref, struct rvin_group, refcount); 106 107 mutex_lock(&rvin_group_lock); 108 109 rvin_group_data = NULL; 110 111 rvin_group_cleanup(group); 112 113 kfree(group); 114 115 mutex_unlock(&rvin_group_lock); 116} 117 118static int rvin_group_get(struct rvin_dev *vin, 119 int (*link_setup)(struct rvin_group *), 120 const struct media_device_ops *ops) 121{ 122 struct rvin_group *group; 123 int ret; 124 125 /* Join or create a VIN group */ 126 mutex_lock(&rvin_group_lock); 127 if (rvin_group_data) { 128 group = rvin_group_data; 129 kref_get(&group->refcount); 130 } else { 131 group = kzalloc(sizeof(*group), GFP_KERNEL); 132 if (!group) { 133 ret = -ENOMEM; 134 goto err_group; 135 } 136 137 ret = rvin_group_init(group, vin, link_setup, ops); 138 if (ret) { 139 kfree(group); 140 vin_err(vin, "Failed to initialize group\n"); 141 goto err_group; 142 } 143 144 kref_init(&group->refcount); 145 group->info = vin->info; 146 147 rvin_group_data = group; 148 } 149 mutex_unlock(&rvin_group_lock); 150 151 /* Add VIN to group */ 152 mutex_lock(&group->lock); 153 154 if (group->vin[vin->id]) { 155 vin_err(vin, "Duplicate renesas,id property value %u\n", vin->id); 156 mutex_unlock(&group->lock); 157 kref_put(&group->refcount, rvin_group_release); 158 return -EINVAL; 159 } 160 161 group->vin[vin->id] = vin; 162 163 vin->group = group; 164 vin->v4l2_dev.mdev = &group->mdev; 165 166 mutex_unlock(&group->lock); 167 168 return 0; 169err_group: 170 mutex_unlock(&rvin_group_lock); 171 return ret; 172} 173 174static void rvin_group_put(struct rvin_dev *vin) 175{ 176 struct rvin_group *group = vin->group; 177 178 mutex_lock(&group->lock); 179 180 vin->group = NULL; 181 vin->v4l2_dev.mdev = NULL; 182 183 if (WARN_ON(group->vin[vin->id] != vin)) 184 goto out; 185 186 group->vin[vin->id] = NULL; 187out: 188 mutex_unlock(&group->lock); 189 190 kref_put(&group->refcount, rvin_group_release); 191} 192 193/* group lock should be held when calling this function. */ 194static int rvin_group_entity_to_remote_id(struct rvin_group *group, 195 struct media_entity *entity) 196{ 197 struct v4l2_subdev *sd; 198 unsigned int i; 199 200 sd = media_entity_to_v4l2_subdev(entity); 201 202 for (i = 0; i < ARRAY_SIZE(group->remotes); i++) 203 if (group->remotes[i].subdev == sd) 204 return i; 205 206 return -ENODEV; 207} 208 209static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) 210{ 211 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); 212 unsigned int i; 213 int ret; 214 215 ret = media_device_register(&vin->group->mdev); 216 if (ret) 217 return ret; 218 219 ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); 220 if (ret) { 221 vin_err(vin, "Failed to register subdev nodes\n"); 222 return ret; 223 } 224 225 /* Register all video nodes for the group. */ 226 for (i = 0; i < RCAR_VIN_NUM; i++) { 227 if (vin->group->vin[i] && 228 !video_is_registered(&vin->group->vin[i]->vdev)) { 229 ret = rvin_v4l2_register(vin->group->vin[i]); 230 if (ret) 231 return ret; 232 } 233 } 234 235 return vin->group->link_setup(vin->group); 236} 237 238static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, 239 struct v4l2_subdev *subdev, 240 struct v4l2_async_connection *asc) 241{ 242 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); 243 struct rvin_group *group = vin->group; 244 245 for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { 246 if (group->vin[i]) 247 rvin_v4l2_unregister(group->vin[i]); 248 } 249 250 mutex_lock(&vin->group->lock); 251 252 for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { 253 if (!group->vin[i] || group->vin[i]->parallel.asc != asc) 254 continue; 255 256 group->vin[i]->parallel.subdev = NULL; 257 258 vin_dbg(group->vin[i], "Unbind parallel subdev %s\n", 259 subdev->name); 260 } 261 262 for (unsigned int i = 0; i < ARRAY_SIZE(group->remotes); i++) { 263 if (group->remotes[i].asc != asc) 264 continue; 265 266 group->remotes[i].subdev = NULL; 267 268 vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); 269 } 270 271 mutex_unlock(&vin->group->lock); 272 273 media_device_unregister(&vin->group->mdev); 274} 275 276static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, 277 struct v4l2_subdev *subdev, 278 struct v4l2_async_connection *asc) 279{ 280 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); 281 struct rvin_group *group = vin->group; 282 283 guard(mutex)(&group->lock); 284 285 for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { 286 struct rvin_dev *pvin = group->vin[i]; 287 288 if (!pvin || pvin->parallel.asc != asc) 289 continue; 290 291 pvin->parallel.source_pad = 0; 292 for (unsigned int pad = 0; pad < subdev->entity.num_pads; pad++) 293 if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE) 294 pvin->parallel.source_pad = pad; 295 296 pvin->parallel.subdev = subdev; 297 vin_dbg(pvin, "Bound subdev %s\n", subdev->name); 298 299 return 0; 300 } 301 302 for (unsigned int i = 0; i < ARRAY_SIZE(group->remotes); i++) { 303 if (vin->group->remotes[i].asc != asc) 304 continue; 305 306 vin->group->remotes[i].subdev = subdev; 307 vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i); 308 309 return 0; 310 } 311 312 return -ENODEV; 313} 314 315static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { 316 .bound = rvin_group_notify_bound, 317 .unbind = rvin_group_notify_unbind, 318 .complete = rvin_group_notify_complete, 319}; 320 321static int rvin_group_parse_of(struct rvin_dev *vin, unsigned int port, 322 unsigned int id) 323{ 324 struct fwnode_handle *ep, *fwnode; 325 struct v4l2_fwnode_endpoint vep = { 326 .bus_type = V4L2_MBUS_CSI2_DPHY, 327 }; 328 struct v4l2_async_connection *asc; 329 int ret; 330 331 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), port, id, 0); 332 if (!ep) 333 return 0; 334 335 fwnode = fwnode_graph_get_remote_endpoint(ep); 336 ret = v4l2_fwnode_endpoint_parse(ep, &vep); 337 fwnode_handle_put(ep); 338 if (ret) { 339 vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode)); 340 ret = -EINVAL; 341 goto out; 342 } 343 344 asc = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode, 345 struct v4l2_async_connection); 346 if (IS_ERR(asc)) { 347 ret = PTR_ERR(asc); 348 goto out; 349 } 350 351 vin->group->remotes[vep.base.id].asc = asc; 352 353 vin_dbg(vin, "Add group OF device %pOF to slot %u\n", 354 to_of_node(fwnode), vep.base.id); 355out: 356 fwnode_handle_put(fwnode); 357 358 return ret; 359} 360 361static int rvin_parallel_parse_of(struct rvin_dev *vin) 362{ 363 struct fwnode_handle *fwnode __free(fwnode_handle) = NULL; 364 struct fwnode_handle *ep __free(fwnode_handle) = NULL; 365 struct v4l2_fwnode_endpoint vep = { 366 .bus_type = V4L2_MBUS_UNKNOWN, 367 }; 368 struct v4l2_async_connection *asc; 369 370 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 0, 0, 0); 371 if (!ep) 372 return 0; 373 374 if (v4l2_fwnode_endpoint_parse(ep, &vep)) { 375 vin_err(vin, "Failed to parse %pOF\n", to_of_node(ep)); 376 return -EINVAL; 377 } 378 379 switch (vep.bus_type) { 380 case V4L2_MBUS_PARALLEL: 381 case V4L2_MBUS_BT656: 382 vin_dbg(vin, "Found %s media bus\n", 383 vep.bus_type == V4L2_MBUS_PARALLEL ? 384 "PARALLEL" : "BT656"); 385 vin->parallel.mbus_type = vep.bus_type; 386 vin->parallel.bus = vep.bus.parallel; 387 break; 388 default: 389 vin_err(vin, "Unknown media bus type\n"); 390 return -EINVAL; 391 } 392 393 fwnode = fwnode_graph_get_remote_endpoint(ep); 394 asc = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode, 395 struct v4l2_async_connection); 396 if (IS_ERR(asc)) 397 return PTR_ERR(asc); 398 399 vin->parallel.asc = asc; 400 401 vin_dbg(vin, "Add parallel OF device %pOF\n", to_of_node(fwnode)); 402 403 return 0; 404} 405 406static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, 407 unsigned int max_id) 408{ 409 unsigned int count = 0, vin_mask = 0; 410 unsigned int i, id; 411 int ret; 412 413 mutex_lock(&vin->group->lock); 414 415 /* If not all VIN's are registered don't register the notifier. */ 416 for (i = 0; i < RCAR_VIN_NUM; i++) { 417 if (vin->group->vin[i]) { 418 count++; 419 vin_mask |= BIT(i); 420 } 421 } 422 423 if (vin->group->count != count) { 424 mutex_unlock(&vin->group->lock); 425 return 0; 426 } 427 428 mutex_unlock(&vin->group->lock); 429 430 v4l2_async_nf_init(&vin->group->notifier, &vin->v4l2_dev); 431 432 /* 433 * Some subdevices may overlap but the parser function can handle it and 434 * each subdevice will only be registered once with the group notifier. 435 */ 436 for (i = 0; i < RCAR_VIN_NUM; i++) { 437 if (!(vin_mask & BIT(i))) 438 continue; 439 440 /* Parse local subdevice. */ 441 ret = rvin_parallel_parse_of(vin->group->vin[i]); 442 if (ret) 443 return ret; 444 445 /* Parse shared subdevices. */ 446 for (id = 0; id < max_id; id++) { 447 if (vin->group->remotes[id].asc) 448 continue; 449 450 ret = rvin_group_parse_of(vin->group->vin[i], port, id); 451 if (ret) 452 return ret; 453 } 454 } 455 456 if (list_empty(&vin->group->notifier.waiting_list)) 457 return 0; 458 459 vin->group->notifier.ops = &rvin_group_notify_ops; 460 ret = v4l2_async_nf_register(&vin->group->notifier); 461 if (ret < 0) { 462 vin_err(vin, "Notifier registration failed\n"); 463 v4l2_async_nf_cleanup(&vin->group->notifier); 464 return ret; 465 } 466 467 return 0; 468} 469 470/* ----------------------------------------------------------------------------- 471 * Controls 472 */ 473 474static int rvin_s_ctrl(struct v4l2_ctrl *ctrl) 475{ 476 struct rvin_dev *vin = 477 container_of(ctrl->handler, struct rvin_dev, ctrl_handler); 478 479 switch (ctrl->id) { 480 case V4L2_CID_ALPHA_COMPONENT: 481 rvin_set_alpha(vin, ctrl->val); 482 break; 483 } 484 485 return 0; 486} 487 488static const struct v4l2_ctrl_ops rvin_ctrl_ops = { 489 .s_ctrl = rvin_s_ctrl, 490}; 491 492static void rvin_free_controls(struct rvin_dev *vin) 493{ 494 v4l2_ctrl_handler_free(&vin->ctrl_handler); 495 vin->vdev.ctrl_handler = NULL; 496} 497 498static int rvin_create_controls(struct rvin_dev *vin) 499{ 500 int ret; 501 502 ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1); 503 if (ret < 0) 504 return ret; 505 506 /* The VIN directly deals with alpha component. */ 507 v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops, 508 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); 509 510 if (vin->ctrl_handler.error) { 511 ret = vin->ctrl_handler.error; 512 rvin_free_controls(vin); 513 return ret; 514 } 515 516 vin->vdev.ctrl_handler = &vin->ctrl_handler; 517 518 return 0; 519} 520 521/* ----------------------------------------------------------------------------- 522 * CSI-2 523 */ 524 525/* 526 * Link setup for the links between a VIN and a CSI-2 receiver is a bit 527 * complex. The reason for this is that the register controlling routing 528 * is not present in each VIN instance. There are special VINs which 529 * control routing for themselves and other VINs. There are not many 530 * different possible links combinations that can be enabled at the same 531 * time, therefor all already enabled links which are controlled by a 532 * master VIN need to be taken into account when making the decision 533 * if a new link can be enabled or not. 534 * 535 * 1. Find out which VIN the link the user tries to enable is connected to. 536 * 2. Lookup which master VIN controls the links for this VIN. 537 * 3. Start with a bitmask with all bits set. 538 * 4. For each previously enabled link from the master VIN bitwise AND its 539 * route mask (see documentation for mask in struct rvin_group_route) 540 * with the bitmask. 541 * 5. Bitwise AND the mask for the link the user tries to enable to the bitmask. 542 * 6. If the bitmask is not empty at this point the new link can be enabled 543 * while keeping all previous links enabled. Update the CHSEL value of the 544 * master VIN and inform the user that the link could be enabled. 545 * 546 * Please note that no link can be enabled if any VIN in the group is 547 * currently open. 548 */ 549static int rvin_csi2_link_notify(struct media_link *link, u32 flags, 550 unsigned int notification) 551{ 552 struct rvin_group *group = container_of(link->graph_obj.mdev, 553 struct rvin_group, mdev); 554 struct media_entity *entity; 555 struct video_device *vdev; 556 struct rvin_dev *vin; 557 unsigned int i; 558 int csi_id, ret; 559 560 ret = v4l2_pipeline_link_notify(link, flags, notification); 561 if (ret) 562 return ret; 563 564 /* Only care about link enablement for VIN nodes. */ 565 if (!(flags & MEDIA_LNK_FL_ENABLED) || 566 !is_media_entity_v4l2_video_device(link->sink->entity)) 567 return 0; 568 569 /* 570 * Don't allow link changes if any stream in the graph is active as 571 * modifying the CHSEL register fields can disrupt running streams. 572 */ 573 media_device_for_each_entity(entity, &group->mdev) 574 if (media_entity_is_streaming(entity)) 575 return -EBUSY; 576 577 /* Find the master VIN that controls the routes. */ 578 vdev = media_entity_to_video_device(link->sink->entity); 579 vin = container_of(vdev, struct rvin_dev, vdev); 580 581 mutex_lock(&group->lock); 582 583 csi_id = rvin_group_entity_to_remote_id(group, link->source->entity); 584 if (csi_id == -ENODEV) { 585 struct v4l2_subdev *sd; 586 587 /* 588 * Make sure the source entity subdevice is registered as 589 * a parallel input of one of the enabled VINs if it is not 590 * one of the CSI-2 subdevices. 591 * 592 * No hardware configuration required for parallel inputs, 593 * we can return here. 594 */ 595 sd = media_entity_to_v4l2_subdev(link->source->entity); 596 for (i = 0; i < RCAR_VIN_NUM; i++) { 597 if (group->vin[i] && 598 group->vin[i]->parallel.subdev == sd) { 599 group->vin[i]->is_csi = false; 600 ret = 0; 601 goto out; 602 } 603 } 604 605 vin_err(vin, "Subdevice %s not registered to any VIN\n", 606 link->source->entity->name); 607 ret = -ENODEV; 608 } else { 609 const struct rvin_group_route *route; 610 unsigned int chsel = UINT_MAX; 611 unsigned int master_id; 612 613 master_id = rvin_group_id_to_master(vin->id); 614 615 if (WARN_ON(!group->vin[master_id])) { 616 ret = -ENODEV; 617 goto out; 618 } 619 620 /* Make sure group is connected to same CSI-2 */ 621 for (i = master_id; i < master_id + 4; i++) { 622 struct media_pad *csi_pad; 623 624 if (!group->vin[i]) 625 continue; 626 627 /* Get remote CSI-2, if any. */ 628 csi_pad = media_pad_remote_pad_first( 629 &group->vin[i]->vdev.entity.pads[0]); 630 if (!csi_pad) 631 continue; 632 633 if (csi_pad->entity != link->source->entity) { 634 vin_dbg(vin, "Already attached to %s\n", 635 csi_pad->entity->name); 636 ret = -EBUSY; 637 goto out; 638 } 639 } 640 641 for (route = vin->info->routes; route->chsel; route++) { 642 if (route->master == master_id && route->csi == csi_id) { 643 chsel = route->chsel; 644 break; 645 } 646 } 647 648 if (chsel == UINT_MAX) { 649 vin_err(vin, "No CHSEL value found\n"); 650 ret = -EINVAL; 651 goto out; 652 } 653 654 ret = rvin_set_channel_routing(group->vin[master_id], chsel); 655 if (ret) 656 goto out; 657 658 vin->is_csi = true; 659 } 660out: 661 mutex_unlock(&group->lock); 662 663 return ret; 664} 665 666static const struct media_device_ops rvin_csi2_media_ops = { 667 .link_notify = rvin_csi2_link_notify, 668}; 669 670static int rvin_csi2_create_link(struct rvin_group *group, unsigned int id, 671 const struct rvin_group_route *route) 672{ 673 struct media_entity *source = &group->remotes[route->csi].subdev->entity; 674 struct media_entity *sink = &group->vin[id]->vdev.entity; 675 struct media_pad *sink_pad = &sink->pads[0]; 676 unsigned int channel; 677 int ret; 678 679 for (channel = 0; channel < 4; channel++) { 680 unsigned int source_idx = rvin_group_csi_channel_to_pad(channel); 681 struct media_pad *source_pad = &source->pads[source_idx]; 682 683 /* Skip if link already exists. */ 684 if (media_entity_find_link(source_pad, sink_pad)) 685 continue; 686 687 ret = media_create_pad_link(source, source_idx, sink, 0, 0); 688 if (ret) 689 return ret; 690 } 691 692 return 0; 693} 694 695static int rvin_parallel_setup_links(struct rvin_group *group) 696{ 697 u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; 698 699 guard(mutex)(&group->lock); 700 701 /* If the group also has links don't enable the link. */ 702 for (unsigned int i = 0; i < ARRAY_SIZE(group->remotes); i++) { 703 if (group->remotes[i].subdev) { 704 flags = 0; 705 break; 706 } 707 } 708 709 /* Create links. */ 710 for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { 711 struct rvin_dev *vin = group->vin[i]; 712 struct media_entity *source; 713 struct media_entity *sink; 714 int ret; 715 716 /* Nothing to do if there is no VIN or parallel subdev. */ 717 if (!vin || !vin->parallel.subdev) 718 continue; 719 720 source = &vin->parallel.subdev->entity; 721 sink = &vin->vdev.entity; 722 723 ret = media_create_pad_link(source, vin->parallel.source_pad, 724 sink, 0, flags); 725 if (ret) 726 return ret; 727 } 728 729 return 0; 730} 731 732static int rvin_csi2_setup_links(struct rvin_group *group) 733{ 734 const struct rvin_group_route *route; 735 unsigned int id; 736 int ret; 737 738 ret = rvin_parallel_setup_links(group); 739 if (ret) 740 return ret; 741 742 /* Create all media device links between VINs and CSI-2's. */ 743 mutex_lock(&group->lock); 744 for (route = group->info->routes; route->chsel; route++) { 745 /* Check that VIN' master is part of the group. */ 746 if (!group->vin[route->master]) 747 continue; 748 749 /* Check that CSI-2 is part of the group. */ 750 if (!group->remotes[route->csi].subdev) 751 continue; 752 753 for (id = route->master; id < route->master + 4; id++) { 754 /* Check that VIN is part of the group. */ 755 if (!group->vin[id]) 756 continue; 757 758 ret = rvin_csi2_create_link(group, id, route); 759 if (ret) 760 goto out; 761 } 762 } 763out: 764 mutex_unlock(&group->lock); 765 766 return ret; 767} 768 769static int rvin_csi2_init(struct rvin_dev *vin) 770{ 771 int ret; 772 773 ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_csi2_media_ops); 774 if (ret) 775 return ret; 776 777 ret = rvin_group_notifier_init(vin, 1, RVIN_CSI_MAX); 778 if (ret) 779 rvin_group_put(vin); 780 781 return ret; 782} 783 784/* ----------------------------------------------------------------------------- 785 * ISP 786 */ 787 788static int rvin_isp_setup_links(struct rvin_group *group) 789{ 790 unsigned int i; 791 int ret = -EINVAL; 792 793 /* Create all media device links between VINs and ISP's. */ 794 mutex_lock(&group->lock); 795 for (i = 0; i < RCAR_VIN_NUM; i++) { 796 struct media_pad *source_pad, *sink_pad; 797 struct media_entity *source, *sink; 798 unsigned int source_slot = i / 8; 799 unsigned int source_idx = i % 8 + 1; 800 struct rvin_dev *vin = group->vin[i]; 801 802 if (!vin) 803 continue; 804 805 /* Check that ISP is part of the group. */ 806 if (!group->remotes[source_slot].subdev) 807 continue; 808 809 source = &group->remotes[source_slot].subdev->entity; 810 source_pad = &source->pads[source_idx]; 811 812 sink = &vin->vdev.entity; 813 sink_pad = &sink->pads[0]; 814 815 /* Skip if link already exists. */ 816 if (media_entity_find_link(source_pad, sink_pad)) 817 continue; 818 819 ret = media_create_pad_link(source, source_idx, sink, 0, 820 MEDIA_LNK_FL_ENABLED | 821 MEDIA_LNK_FL_IMMUTABLE); 822 if (ret) { 823 vin_err(vin, "Error adding link from %s to %s\n", 824 source->name, sink->name); 825 break; 826 } 827 } 828 mutex_unlock(&group->lock); 829 830 return ret; 831} 832 833static int rvin_isp_init(struct rvin_dev *vin) 834{ 835 int ret; 836 837 ret = rvin_group_get(vin, rvin_isp_setup_links, NULL); 838 if (ret) 839 return ret; 840 841 ret = rvin_group_notifier_init(vin, 2, RVIN_ISP_MAX); 842 if (ret) 843 rvin_group_put(vin); 844 845 return ret; 846} 847 848/* ----------------------------------------------------------------------------- 849 * Suspend / Resume 850 */ 851 852static int rvin_suspend(struct device *dev) 853{ 854 struct rvin_dev *vin = dev_get_drvdata(dev); 855 856 if (!vin->running) 857 return 0; 858 859 rvin_stop_streaming(vin); 860 861 return 0; 862} 863 864static int rvin_resume(struct device *dev) 865{ 866 struct rvin_dev *vin = dev_get_drvdata(dev); 867 868 if (!vin->running) 869 return 0; 870 871 /* 872 * Restore group master CHSEL setting. 873 * 874 * This needs to be done by every VIN resuming not only the master 875 * as we don't know if and in which order the master VINs will 876 * be resumed. 877 */ 878 if (vin->info->model == RCAR_GEN3) { 879 unsigned int master_id = rvin_group_id_to_master(vin->id); 880 struct rvin_dev *master = vin->group->vin[master_id]; 881 int ret; 882 883 if (WARN_ON(!master)) 884 return -ENODEV; 885 886 ret = rvin_set_channel_routing(master, master->chsel); 887 if (ret) 888 return ret; 889 } 890 891 return rvin_start_streaming(vin); 892} 893 894/* ----------------------------------------------------------------------------- 895 * Platform Device Driver 896 */ 897 898static const struct rvin_info rcar_info_h1 = { 899 .model = RCAR_H1, 900 .max_width = 2048, 901 .max_height = 2048, 902 .scaler = rvin_scaler_gen2, 903}; 904 905static const struct rvin_info rcar_info_m1 = { 906 .model = RCAR_M1, 907 .max_width = 2048, 908 .max_height = 2048, 909 .scaler = rvin_scaler_gen2, 910}; 911 912static const struct rvin_info rcar_info_gen2 = { 913 .model = RCAR_GEN2, 914 .max_width = 2048, 915 .max_height = 2048, 916 .scaler = rvin_scaler_gen2, 917}; 918 919static const struct rvin_group_route rcar_info_r8a774e1_routes[] = { 920 { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 }, 921 { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, 922 { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 }, 923 { /* Sentinel */ } 924}; 925 926static const struct rvin_info rcar_info_r8a774e1 = { 927 .model = RCAR_GEN3, 928 .max_width = 4096, 929 .max_height = 4096, 930 .routes = rcar_info_r8a774e1_routes, 931}; 932 933static const struct rvin_group_route rcar_info_r8a7795_routes[] = { 934 { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 }, 935 { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, 936 { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 }, 937 { .master = 4, .csi = RVIN_CSI41, .chsel = 0x03 }, 938 { /* Sentinel */ } 939}; 940 941static const struct rvin_info rcar_info_r8a7795 = { 942 .model = RCAR_GEN3, 943 .nv12 = true, 944 .max_width = 4096, 945 .max_height = 4096, 946 .routes = rcar_info_r8a7795_routes, 947 .scaler = rvin_scaler_gen3, 948}; 949 950static const struct rvin_group_route rcar_info_r8a7796_routes[] = { 951 { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 }, 952 { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, 953 { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 }, 954 { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 }, 955 { /* Sentinel */ } 956}; 957 958static const struct rvin_info rcar_info_r8a7796 = { 959 .model = RCAR_GEN3, 960 .nv12 = true, 961 .max_width = 4096, 962 .max_height = 4096, 963 .routes = rcar_info_r8a7796_routes, 964 .scaler = rvin_scaler_gen3, 965}; 966 967static const struct rvin_group_route rcar_info_r8a77965_routes[] = { 968 { .master = 0, .csi = RVIN_CSI20, .chsel = 0x04 }, 969 { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, 970 { .master = 4, .csi = RVIN_CSI20, .chsel = 0x04 }, 971 { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 }, 972 { /* Sentinel */ } 973}; 974 975static const struct rvin_info rcar_info_r8a77965 = { 976 .model = RCAR_GEN3, 977 .nv12 = true, 978 .max_width = 4096, 979 .max_height = 4096, 980 .routes = rcar_info_r8a77965_routes, 981 .scaler = rvin_scaler_gen3, 982}; 983 984static const struct rvin_group_route rcar_info_r8a77970_routes[] = { 985 { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, 986 { /* Sentinel */ } 987}; 988 989static const struct rvin_info rcar_info_r8a77970 = { 990 .model = RCAR_GEN3, 991 .max_width = 4096, 992 .max_height = 4096, 993 .routes = rcar_info_r8a77970_routes, 994}; 995 996static const struct rvin_group_route rcar_info_r8a77980_routes[] = { 997 { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, 998 { .master = 4, .csi = RVIN_CSI41, .chsel = 0x03 }, 999 { /* Sentinel */ } 1000}; 1001 1002static const struct rvin_info rcar_info_r8a77980 = { 1003 .model = RCAR_GEN3, 1004 .nv12 = true, 1005 .max_width = 4096, 1006 .max_height = 4096, 1007 .routes = rcar_info_r8a77980_routes, 1008}; 1009 1010static const struct rvin_group_route rcar_info_r8a77990_routes[] = { 1011 { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 }, 1012 { /* Sentinel */ } 1013}; 1014 1015static const struct rvin_info rcar_info_r8a77990 = { 1016 .model = RCAR_GEN3, 1017 .nv12 = true, 1018 .max_width = 4096, 1019 .max_height = 4096, 1020 .routes = rcar_info_r8a77990_routes, 1021 .scaler = rvin_scaler_gen3, 1022}; 1023 1024static const struct rvin_group_route rcar_info_r8a77995_routes[] = { 1025 { /* Sentinel */ } 1026}; 1027 1028static const struct rvin_info rcar_info_r8a77995 = { 1029 .model = RCAR_GEN3, 1030 .nv12 = true, 1031 .max_width = 4096, 1032 .max_height = 4096, 1033 .routes = rcar_info_r8a77995_routes, 1034 .scaler = rvin_scaler_gen3, 1035}; 1036 1037static const struct rvin_info rcar_info_gen4 = { 1038 .model = RCAR_GEN4, 1039 .use_isp = true, 1040 .nv12 = true, 1041 .raw10 = true, 1042 .max_width = 4096, 1043 .max_height = 4096, 1044}; 1045 1046static const struct of_device_id rvin_of_id_table[] = { 1047 { 1048 .compatible = "renesas,vin-r8a774a1", 1049 .data = &rcar_info_r8a7796, 1050 }, 1051 { 1052 .compatible = "renesas,vin-r8a774b1", 1053 .data = &rcar_info_r8a77965, 1054 }, 1055 { 1056 .compatible = "renesas,vin-r8a774c0", 1057 .data = &rcar_info_r8a77990, 1058 }, 1059 { 1060 .compatible = "renesas,vin-r8a774e1", 1061 .data = &rcar_info_r8a774e1, 1062 }, 1063 { 1064 .compatible = "renesas,vin-r8a7778", 1065 .data = &rcar_info_m1, 1066 }, 1067 { 1068 .compatible = "renesas,vin-r8a7779", 1069 .data = &rcar_info_h1, 1070 }, 1071 { 1072 .compatible = "renesas,rcar-gen2-vin", 1073 .data = &rcar_info_gen2, 1074 }, 1075 { 1076 .compatible = "renesas,vin-r8a7795", 1077 .data = &rcar_info_r8a7795, 1078 }, 1079 { 1080 .compatible = "renesas,vin-r8a7796", 1081 .data = &rcar_info_r8a7796, 1082 }, 1083 { 1084 .compatible = "renesas,vin-r8a77961", 1085 .data = &rcar_info_r8a7796, 1086 }, 1087 { 1088 .compatible = "renesas,vin-r8a77965", 1089 .data = &rcar_info_r8a77965, 1090 }, 1091 { 1092 .compatible = "renesas,vin-r8a77970", 1093 .data = &rcar_info_r8a77970, 1094 }, 1095 { 1096 .compatible = "renesas,vin-r8a77980", 1097 .data = &rcar_info_r8a77980, 1098 }, 1099 { 1100 .compatible = "renesas,vin-r8a77990", 1101 .data = &rcar_info_r8a77990, 1102 }, 1103 { 1104 .compatible = "renesas,vin-r8a77995", 1105 .data = &rcar_info_r8a77995, 1106 }, 1107 { 1108 /* Keep to be compatible with old DTS files. */ 1109 .compatible = "renesas,vin-r8a779a0", 1110 .data = &rcar_info_gen4, 1111 }, 1112 { 1113 /* Keep to be compatible with old DTS files. */ 1114 .compatible = "renesas,vin-r8a779g0", 1115 .data = &rcar_info_gen4, 1116 }, 1117 { 1118 .compatible = "renesas,rcar-gen4-vin", 1119 .data = &rcar_info_gen4, 1120 }, 1121 { /* Sentinel */ }, 1122}; 1123MODULE_DEVICE_TABLE(of, rvin_of_id_table); 1124 1125static int rvin_id_get(struct rvin_dev *vin) 1126{ 1127 u32 oid; 1128 int id; 1129 1130 switch (vin->info->model) { 1131 case RCAR_GEN3: 1132 case RCAR_GEN4: 1133 if (of_property_read_u32(vin->dev->of_node, "renesas,id", &oid)) { 1134 vin_err(vin, "%pOF: No renesas,id property found\n", 1135 vin->dev->of_node); 1136 return -EINVAL; 1137 } 1138 1139 if (oid < 0 || oid >= RCAR_VIN_NUM) { 1140 vin_err(vin, "%pOF: Invalid renesas,id '%u'\n", 1141 vin->dev->of_node, oid); 1142 return -EINVAL; 1143 } 1144 1145 vin->id = oid; 1146 break; 1147 default: 1148 id = ida_alloc_range(&rvin_ida, 0, RCAR_VIN_NUM - 1, 1149 GFP_KERNEL); 1150 if (id < 0) { 1151 vin_err(vin, "%pOF: Failed to allocate VIN group ID\n", 1152 vin->dev->of_node); 1153 return -EINVAL; 1154 } 1155 1156 vin->id = id; 1157 break; 1158 } 1159 1160 return 0; 1161} 1162 1163static void rvin_id_put(struct rvin_dev *vin) 1164{ 1165 switch (vin->info->model) { 1166 case RCAR_GEN3: 1167 case RCAR_GEN4: 1168 break; 1169 default: 1170 ida_free(&rvin_ida, vin->id); 1171 break; 1172 } 1173} 1174 1175static int rcar_vin_probe(struct platform_device *pdev) 1176{ 1177 struct rvin_dev *vin; 1178 int irq, ret; 1179 1180 vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL); 1181 if (!vin) 1182 return -ENOMEM; 1183 1184 vin->dev = &pdev->dev; 1185 vin->info = of_device_get_match_data(&pdev->dev); 1186 vin->alpha = 0xff; 1187 1188 vin->base = devm_platform_ioremap_resource(pdev, 0); 1189 if (IS_ERR(vin->base)) 1190 return PTR_ERR(vin->base); 1191 1192 irq = platform_get_irq(pdev, 0); 1193 if (irq < 0) 1194 return irq; 1195 1196 ret = rvin_dma_register(vin, irq); 1197 if (ret) 1198 return ret; 1199 1200 platform_set_drvdata(pdev, vin); 1201 1202 if (rvin_id_get(vin)) { 1203 ret = -EINVAL; 1204 goto err_dma; 1205 } 1206 1207 vin->pad.flags = MEDIA_PAD_FL_SINK; 1208 ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); 1209 if (ret) 1210 goto err_id; 1211 1212 ret = rvin_create_controls(vin); 1213 if (ret < 0) 1214 goto err_id; 1215 1216 switch (vin->info->model) { 1217 case RCAR_GEN3: 1218 case RCAR_GEN4: 1219 if (vin->info->use_isp) { 1220 ret = rvin_isp_init(vin); 1221 } else { 1222 ret = rvin_csi2_init(vin); 1223 1224 if (vin->info->scaler && 1225 rvin_group_id_to_master(vin->id) == vin->id) 1226 vin->scaler = vin->info->scaler; 1227 } 1228 break; 1229 default: 1230 ret = rvin_group_get(vin, rvin_parallel_setup_links, NULL); 1231 if (!ret) 1232 ret = rvin_group_notifier_init(vin, 0, 0); 1233 1234 if (vin->info->scaler) 1235 vin->scaler = vin->info->scaler; 1236 break; 1237 } 1238 1239 if (ret) 1240 goto err_ctrl; 1241 1242 pm_suspend_ignore_children(&pdev->dev, true); 1243 pm_runtime_enable(&pdev->dev); 1244 1245 return 0; 1246 1247err_ctrl: 1248 rvin_free_controls(vin); 1249err_id: 1250 rvin_id_put(vin); 1251err_dma: 1252 rvin_dma_unregister(vin); 1253 1254 return ret; 1255} 1256 1257static void rcar_vin_remove(struct platform_device *pdev) 1258{ 1259 struct rvin_dev *vin = platform_get_drvdata(pdev); 1260 1261 pm_runtime_disable(&pdev->dev); 1262 1263 rvin_v4l2_unregister(vin); 1264 1265 if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { 1266 v4l2_async_nf_unregister(&vin->group->notifier); 1267 v4l2_async_nf_cleanup(&vin->group->notifier); 1268 } 1269 1270 rvin_group_put(vin); 1271 1272 rvin_free_controls(vin); 1273 1274 rvin_id_put(vin); 1275 1276 rvin_dma_unregister(vin); 1277} 1278 1279static DEFINE_SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume); 1280 1281static struct platform_driver rcar_vin_driver = { 1282 .driver = { 1283 .name = "rcar-vin", 1284 .suppress_bind_attrs = true, 1285 .pm = pm_sleep_ptr(&rvin_pm_ops), 1286 .of_match_table = rvin_of_id_table, 1287 }, 1288 .probe = rcar_vin_probe, 1289 .remove = rcar_vin_remove, 1290}; 1291 1292module_platform_driver(rcar_vin_driver); 1293 1294MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); 1295MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver"); 1296MODULE_LICENSE("GPL");
~/
Read-only file preview.