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