linux/drivers/media/platform/vsp1/vsp1_drv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * vsp1_drv.c  --  R-Car VSP1 Driver
   4 *
   5 * Copyright (C) 2013-2015 Renesas Electronics Corporation
   6 *
   7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/delay.h>
  12#include <linux/device.h>
  13#include <linux/interrupt.h>
  14#include <linux/module.h>
  15#include <linux/of.h>
  16#include <linux/of_device.h>
  17#include <linux/platform_device.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/videodev2.h>
  20
  21#include <media/rcar-fcp.h>
  22#include <media/v4l2-subdev.h>
  23
  24#include "vsp1.h"
  25#include "vsp1_brx.h"
  26#include "vsp1_clu.h"
  27#include "vsp1_dl.h"
  28#include "vsp1_drm.h"
  29#include "vsp1_hgo.h"
  30#include "vsp1_hgt.h"
  31#include "vsp1_hsit.h"
  32#include "vsp1_lif.h"
  33#include "vsp1_lut.h"
  34#include "vsp1_pipe.h"
  35#include "vsp1_rwpf.h"
  36#include "vsp1_sru.h"
  37#include "vsp1_uds.h"
  38#include "vsp1_uif.h"
  39#include "vsp1_video.h"
  40
  41/* -----------------------------------------------------------------------------
  42 * Interrupt Handling
  43 */
  44
  45static irqreturn_t vsp1_irq_handler(int irq, void *data)
  46{
  47        u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
  48        struct vsp1_device *vsp1 = data;
  49        irqreturn_t ret = IRQ_NONE;
  50        unsigned int i;
  51        u32 status;
  52
  53        for (i = 0; i < vsp1->info->wpf_count; ++i) {
  54                struct vsp1_rwpf *wpf = vsp1->wpf[i];
  55
  56                if (wpf == NULL)
  57                        continue;
  58
  59                status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
  60                vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
  61
  62                if (status & VI6_WFP_IRQ_STA_DFE) {
  63                        vsp1_pipeline_frame_end(wpf->entity.pipe);
  64                        ret = IRQ_HANDLED;
  65                }
  66        }
  67
  68        return ret;
  69}
  70
  71/* -----------------------------------------------------------------------------
  72 * Entities
  73 */
  74
  75/*
  76 * vsp1_create_sink_links - Create links from all sources to the given sink
  77 *
  78 * This function creates media links from all valid sources to the given sink
  79 * pad. Links that would be invalid according to the VSP1 hardware capabilities
  80 * are skipped. Those include all links
  81 *
  82 * - from a UDS to a UDS (UDS entities can't be chained)
  83 * - from an entity to itself (no loops are allowed)
  84 *
  85 * Furthermore, the BRS can't be connected to histogram generators, but no
  86 * special check is currently needed as all VSP instances that include a BRS
  87 * have no histogram generator.
  88 */
  89static int vsp1_create_sink_links(struct vsp1_device *vsp1,
  90                                  struct vsp1_entity *sink)
  91{
  92        struct media_entity *entity = &sink->subdev.entity;
  93        struct vsp1_entity *source;
  94        unsigned int pad;
  95        int ret;
  96
  97        list_for_each_entry(source, &vsp1->entities, list_dev) {
  98                u32 flags;
  99
 100                if (source->type == sink->type)
 101                        continue;
 102
 103                if (source->type == VSP1_ENTITY_HGO ||
 104                    source->type == VSP1_ENTITY_HGT ||
 105                    source->type == VSP1_ENTITY_LIF ||
 106                    source->type == VSP1_ENTITY_WPF)
 107                        continue;
 108
 109                flags = source->type == VSP1_ENTITY_RPF &&
 110                        sink->type == VSP1_ENTITY_WPF &&
 111                        source->index == sink->index
 112                      ? MEDIA_LNK_FL_ENABLED : 0;
 113
 114                for (pad = 0; pad < entity->num_pads; ++pad) {
 115                        if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
 116                                continue;
 117
 118                        ret = media_create_pad_link(&source->subdev.entity,
 119                                                       source->source_pad,
 120                                                       entity, pad, flags);
 121                        if (ret < 0)
 122                                return ret;
 123
 124                        if (flags & MEDIA_LNK_FL_ENABLED)
 125                                source->sink = sink;
 126                }
 127        }
 128
 129        return 0;
 130}
 131
 132static int vsp1_uapi_create_links(struct vsp1_device *vsp1)
 133{
 134        struct vsp1_entity *entity;
 135        unsigned int i;
 136        int ret;
 137
 138        list_for_each_entry(entity, &vsp1->entities, list_dev) {
 139                if (entity->type == VSP1_ENTITY_LIF ||
 140                    entity->type == VSP1_ENTITY_RPF)
 141                        continue;
 142
 143                ret = vsp1_create_sink_links(vsp1, entity);
 144                if (ret < 0)
 145                        return ret;
 146        }
 147
 148        if (vsp1->hgo) {
 149                ret = media_create_pad_link(&vsp1->hgo->histo.entity.subdev.entity,
 150                                            HISTO_PAD_SOURCE,
 151                                            &vsp1->hgo->histo.video.entity, 0,
 152                                            MEDIA_LNK_FL_ENABLED |
 153                                            MEDIA_LNK_FL_IMMUTABLE);
 154                if (ret < 0)
 155                        return ret;
 156        }
 157
 158        if (vsp1->hgt) {
 159                ret = media_create_pad_link(&vsp1->hgt->histo.entity.subdev.entity,
 160                                            HISTO_PAD_SOURCE,
 161                                            &vsp1->hgt->histo.video.entity, 0,
 162                                            MEDIA_LNK_FL_ENABLED |
 163                                            MEDIA_LNK_FL_IMMUTABLE);
 164                if (ret < 0)
 165                        return ret;
 166        }
 167
 168        for (i = 0; i < vsp1->info->lif_count; ++i) {
 169                if (!vsp1->lif[i])
 170                        continue;
 171
 172                ret = media_create_pad_link(&vsp1->wpf[i]->entity.subdev.entity,
 173                                            RWPF_PAD_SOURCE,
 174                                            &vsp1->lif[i]->entity.subdev.entity,
 175                                            LIF_PAD_SINK, 0);
 176                if (ret < 0)
 177                        return ret;
 178        }
 179
 180        for (i = 0; i < vsp1->info->rpf_count; ++i) {
 181                struct vsp1_rwpf *rpf = vsp1->rpf[i];
 182
 183                ret = media_create_pad_link(&rpf->video->video.entity, 0,
 184                                            &rpf->entity.subdev.entity,
 185                                            RWPF_PAD_SINK,
 186                                            MEDIA_LNK_FL_ENABLED |
 187                                            MEDIA_LNK_FL_IMMUTABLE);
 188                if (ret < 0)
 189                        return ret;
 190        }
 191
 192        for (i = 0; i < vsp1->info->wpf_count; ++i) {
 193                /*
 194                 * Connect the video device to the WPF. All connections are
 195                 * immutable.
 196                 */
 197                struct vsp1_rwpf *wpf = vsp1->wpf[i];
 198
 199                ret = media_create_pad_link(&wpf->entity.subdev.entity,
 200                                            RWPF_PAD_SOURCE,
 201                                            &wpf->video->video.entity, 0,
 202                                            MEDIA_LNK_FL_IMMUTABLE |
 203                                            MEDIA_LNK_FL_ENABLED);
 204                if (ret < 0)
 205                        return ret;
 206        }
 207
 208        return 0;
 209}
 210
 211static void vsp1_destroy_entities(struct vsp1_device *vsp1)
 212{
 213        struct vsp1_entity *entity, *_entity;
 214        struct vsp1_video *video, *_video;
 215
 216        list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) {
 217                list_del(&entity->list_dev);
 218                vsp1_entity_destroy(entity);
 219        }
 220
 221        list_for_each_entry_safe(video, _video, &vsp1->videos, list) {
 222                list_del(&video->list);
 223                vsp1_video_cleanup(video);
 224        }
 225
 226        v4l2_device_unregister(&vsp1->v4l2_dev);
 227        if (vsp1->info->uapi)
 228                media_device_unregister(&vsp1->media_dev);
 229        media_device_cleanup(&vsp1->media_dev);
 230
 231        if (!vsp1->info->uapi)
 232                vsp1_drm_cleanup(vsp1);
 233}
 234
 235static int vsp1_create_entities(struct vsp1_device *vsp1)
 236{
 237        struct media_device *mdev = &vsp1->media_dev;
 238        struct v4l2_device *vdev = &vsp1->v4l2_dev;
 239        struct vsp1_entity *entity;
 240        unsigned int i;
 241        int ret;
 242
 243        mdev->dev = vsp1->dev;
 244        mdev->hw_revision = vsp1->version;
 245        strscpy(mdev->model, vsp1->info->model, sizeof(mdev->model));
 246        snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
 247                 dev_name(mdev->dev));
 248        media_device_init(mdev);
 249
 250        vsp1->media_ops.link_setup = vsp1_entity_link_setup;
 251        /*
 252         * Don't perform link validation when the userspace API is disabled as
 253         * the pipeline is configured internally by the driver in that case, and
 254         * its configuration can thus be trusted.
 255         */
 256        if (vsp1->info->uapi)
 257                vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
 258
 259        vdev->mdev = mdev;
 260        ret = v4l2_device_register(vsp1->dev, vdev);
 261        if (ret < 0) {
 262                dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
 263                        ret);
 264                goto done;
 265        }
 266
 267        /* Instantiate all the entities. */
 268        if (vsp1->info->features & VSP1_HAS_BRS) {
 269                vsp1->brs = vsp1_brx_create(vsp1, VSP1_ENTITY_BRS);
 270                if (IS_ERR(vsp1->brs)) {
 271                        ret = PTR_ERR(vsp1->brs);
 272                        goto done;
 273                }
 274
 275                list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities);
 276        }
 277
 278        if (vsp1->info->features & VSP1_HAS_BRU) {
 279                vsp1->bru = vsp1_brx_create(vsp1, VSP1_ENTITY_BRU);
 280                if (IS_ERR(vsp1->bru)) {
 281                        ret = PTR_ERR(vsp1->bru);
 282                        goto done;
 283                }
 284
 285                list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
 286        }
 287
 288        if (vsp1->info->features & VSP1_HAS_CLU) {
 289                vsp1->clu = vsp1_clu_create(vsp1);
 290                if (IS_ERR(vsp1->clu)) {
 291                        ret = PTR_ERR(vsp1->clu);
 292                        goto done;
 293                }
 294
 295                list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities);
 296        }
 297
 298        vsp1->hsi = vsp1_hsit_create(vsp1, true);
 299        if (IS_ERR(vsp1->hsi)) {
 300                ret = PTR_ERR(vsp1->hsi);
 301                goto done;
 302        }
 303
 304        list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
 305
 306        vsp1->hst = vsp1_hsit_create(vsp1, false);
 307        if (IS_ERR(vsp1->hst)) {
 308                ret = PTR_ERR(vsp1->hst);
 309                goto done;
 310        }
 311
 312        list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
 313
 314        if (vsp1->info->features & VSP1_HAS_HGO && vsp1->info->uapi) {
 315                vsp1->hgo = vsp1_hgo_create(vsp1);
 316                if (IS_ERR(vsp1->hgo)) {
 317                        ret = PTR_ERR(vsp1->hgo);
 318                        goto done;
 319                }
 320
 321                list_add_tail(&vsp1->hgo->histo.entity.list_dev,
 322                              &vsp1->entities);
 323        }
 324
 325        if (vsp1->info->features & VSP1_HAS_HGT && vsp1->info->uapi) {
 326                vsp1->hgt = vsp1_hgt_create(vsp1);
 327                if (IS_ERR(vsp1->hgt)) {
 328                        ret = PTR_ERR(vsp1->hgt);
 329                        goto done;
 330                }
 331
 332                list_add_tail(&vsp1->hgt->histo.entity.list_dev,
 333                              &vsp1->entities);
 334        }
 335
 336        /*
 337         * The LIFs are only supported when used in conjunction with the DU, in
 338         * which case the userspace API is disabled. If the userspace API is
 339         * enabled skip the LIFs, even when present.
 340         */
 341        if (!vsp1->info->uapi) {
 342                for (i = 0; i < vsp1->info->lif_count; ++i) {
 343                        struct vsp1_lif *lif;
 344
 345                        lif = vsp1_lif_create(vsp1, i);
 346                        if (IS_ERR(lif)) {
 347                                ret = PTR_ERR(lif);
 348                                goto done;
 349                        }
 350
 351                        vsp1->lif[i] = lif;
 352                        list_add_tail(&lif->entity.list_dev, &vsp1->entities);
 353                }
 354        }
 355
 356        if (vsp1->info->features & VSP1_HAS_LUT) {
 357                vsp1->lut = vsp1_lut_create(vsp1);
 358                if (IS_ERR(vsp1->lut)) {
 359                        ret = PTR_ERR(vsp1->lut);
 360                        goto done;
 361                }
 362
 363                list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
 364        }
 365
 366        for (i = 0; i < vsp1->info->rpf_count; ++i) {
 367                struct vsp1_rwpf *rpf;
 368
 369                rpf = vsp1_rpf_create(vsp1, i);
 370                if (IS_ERR(rpf)) {
 371                        ret = PTR_ERR(rpf);
 372                        goto done;
 373                }
 374
 375                vsp1->rpf[i] = rpf;
 376                list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
 377
 378                if (vsp1->info->uapi) {
 379                        struct vsp1_video *video = vsp1_video_create(vsp1, rpf);
 380
 381                        if (IS_ERR(video)) {
 382                                ret = PTR_ERR(video);
 383                                goto done;
 384                        }
 385
 386                        list_add_tail(&video->list, &vsp1->videos);
 387                }
 388        }
 389
 390        if (vsp1->info->features & VSP1_HAS_SRU) {
 391                vsp1->sru = vsp1_sru_create(vsp1);
 392                if (IS_ERR(vsp1->sru)) {
 393                        ret = PTR_ERR(vsp1->sru);
 394                        goto done;
 395                }
 396
 397                list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
 398        }
 399
 400        for (i = 0; i < vsp1->info->uds_count; ++i) {
 401                struct vsp1_uds *uds;
 402
 403                uds = vsp1_uds_create(vsp1, i);
 404                if (IS_ERR(uds)) {
 405                        ret = PTR_ERR(uds);
 406                        goto done;
 407                }
 408
 409                vsp1->uds[i] = uds;
 410                list_add_tail(&uds->entity.list_dev, &vsp1->entities);
 411        }
 412
 413        for (i = 0; i < vsp1->info->uif_count; ++i) {
 414                struct vsp1_uif *uif;
 415
 416                uif = vsp1_uif_create(vsp1, i);
 417                if (IS_ERR(uif)) {
 418                        ret = PTR_ERR(uif);
 419                        goto done;
 420                }
 421
 422                vsp1->uif[i] = uif;
 423                list_add_tail(&uif->entity.list_dev, &vsp1->entities);
 424        }
 425
 426        for (i = 0; i < vsp1->info->wpf_count; ++i) {
 427                struct vsp1_rwpf *wpf;
 428
 429                wpf = vsp1_wpf_create(vsp1, i);
 430                if (IS_ERR(wpf)) {
 431                        ret = PTR_ERR(wpf);
 432                        goto done;
 433                }
 434
 435                vsp1->wpf[i] = wpf;
 436                list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
 437
 438                if (vsp1->info->uapi) {
 439                        struct vsp1_video *video = vsp1_video_create(vsp1, wpf);
 440
 441                        if (IS_ERR(video)) {
 442                                ret = PTR_ERR(video);
 443                                goto done;
 444                        }
 445
 446                        list_add_tail(&video->list, &vsp1->videos);
 447                }
 448        }
 449
 450        /* Register all subdevs. */
 451        list_for_each_entry(entity, &vsp1->entities, list_dev) {
 452                ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
 453                                                  &entity->subdev);
 454                if (ret < 0)
 455                        goto done;
 456        }
 457
 458        /*
 459         * Create links and register subdev nodes if the userspace API is
 460         * enabled or initialize the DRM pipeline otherwise.
 461         */
 462        if (vsp1->info->uapi) {
 463                ret = vsp1_uapi_create_links(vsp1);
 464                if (ret < 0)
 465                        goto done;
 466
 467                ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
 468                if (ret < 0)
 469                        goto done;
 470
 471                ret = media_device_register(mdev);
 472        } else {
 473                ret = vsp1_drm_init(vsp1);
 474        }
 475
 476done:
 477        if (ret < 0)
 478                vsp1_destroy_entities(vsp1);
 479
 480        return ret;
 481}
 482
 483int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
 484{
 485        unsigned int timeout;
 486        u32 status;
 487
 488        status = vsp1_read(vsp1, VI6_STATUS);
 489        if (!(status & VI6_STATUS_SYS_ACT(index)))
 490                return 0;
 491
 492        vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
 493        for (timeout = 10; timeout > 0; --timeout) {
 494                status = vsp1_read(vsp1, VI6_STATUS);
 495                if (!(status & VI6_STATUS_SYS_ACT(index)))
 496                        break;
 497
 498                usleep_range(1000, 2000);
 499        }
 500
 501        if (!timeout) {
 502                dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
 503                return -ETIMEDOUT;
 504        }
 505
 506        return 0;
 507}
 508
 509static int vsp1_device_init(struct vsp1_device *vsp1)
 510{
 511        unsigned int i;
 512        int ret;
 513
 514        /* Reset any channel that might be running. */
 515        for (i = 0; i < vsp1->info->wpf_count; ++i) {
 516                ret = vsp1_reset_wpf(vsp1, i);
 517                if (ret < 0)
 518                        return ret;
 519        }
 520
 521        vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
 522                   (8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
 523
 524        for (i = 0; i < vsp1->info->rpf_count; ++i)
 525                vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
 526
 527        for (i = 0; i < vsp1->info->uds_count; ++i)
 528                vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
 529
 530        for (i = 0; i < vsp1->info->uif_count; ++i)
 531                vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED);
 532
 533        vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
 534        vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
 535        vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
 536        vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
 537        vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
 538        vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
 539
 540        if (vsp1->info->features & VSP1_HAS_BRS)
 541                vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED);
 542
 543        vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 544                   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 545        vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
 546                   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
 547
 548        vsp1_dlm_setup(vsp1);
 549
 550        return 0;
 551}
 552
 553/*
 554 * vsp1_device_get - Acquire the VSP1 device
 555 *
 556 * Make sure the device is not suspended and initialize it if needed.
 557 *
 558 * Return 0 on success or a negative error code otherwise.
 559 */
 560int vsp1_device_get(struct vsp1_device *vsp1)
 561{
 562        int ret;
 563
 564        ret = pm_runtime_get_sync(vsp1->dev);
 565        return ret < 0 ? ret : 0;
 566}
 567
 568/*
 569 * vsp1_device_put - Release the VSP1 device
 570 *
 571 * Decrement the VSP1 reference count and cleanup the device if the last
 572 * reference is released.
 573 */
 574void vsp1_device_put(struct vsp1_device *vsp1)
 575{
 576        pm_runtime_put_sync(vsp1->dev);
 577}
 578
 579/* -----------------------------------------------------------------------------
 580 * Power Management
 581 */
 582
 583static int __maybe_unused vsp1_pm_suspend(struct device *dev)
 584{
 585        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 586
 587        /*
 588         * When used as part of a display pipeline, the VSP is stopped and
 589         * restarted explicitly by the DU.
 590         */
 591        if (!vsp1->drm)
 592                vsp1_video_suspend(vsp1);
 593
 594        pm_runtime_force_suspend(vsp1->dev);
 595
 596        return 0;
 597}
 598
 599static int __maybe_unused vsp1_pm_resume(struct device *dev)
 600{
 601        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 602
 603        pm_runtime_force_resume(vsp1->dev);
 604
 605        /*
 606         * When used as part of a display pipeline, the VSP is stopped and
 607         * restarted explicitly by the DU.
 608         */
 609        if (!vsp1->drm)
 610                vsp1_video_resume(vsp1);
 611
 612        return 0;
 613}
 614
 615static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev)
 616{
 617        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 618
 619        rcar_fcp_disable(vsp1->fcp);
 620
 621        return 0;
 622}
 623
 624static int __maybe_unused vsp1_pm_runtime_resume(struct device *dev)
 625{
 626        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 627        int ret;
 628
 629        if (vsp1->info) {
 630                ret = vsp1_device_init(vsp1);
 631                if (ret < 0)
 632                        return ret;
 633        }
 634
 635        return rcar_fcp_enable(vsp1->fcp);
 636}
 637
 638static const struct dev_pm_ops vsp1_pm_ops = {
 639        SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
 640        SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL)
 641};
 642
 643/* -----------------------------------------------------------------------------
 644 * Platform Driver
 645 */
 646
 647static const struct vsp1_device_info vsp1_device_infos[] = {
 648        {
 649                .version = VI6_IP_VERSION_MODEL_VSPS_H2,
 650                .model = "VSP1-S",
 651                .gen = 2,
 652                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
 653                          | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
 654                          | VSP1_HAS_WPF_VFLIP,
 655                .rpf_count = 5,
 656                .uds_count = 3,
 657                .wpf_count = 4,
 658                .num_bru_inputs = 4,
 659                .uapi = true,
 660        }, {
 661                .version = VI6_IP_VERSION_MODEL_VSPR_H2,
 662                .model = "VSP1-R",
 663                .gen = 2,
 664                .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
 665                .rpf_count = 5,
 666                .uds_count = 3,
 667                .wpf_count = 4,
 668                .num_bru_inputs = 4,
 669                .uapi = true,
 670        }, {
 671                .version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
 672                .model = "VSP1-D",
 673                .gen = 2,
 674                .features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT,
 675                .lif_count = 1,
 676                .rpf_count = 4,
 677                .uds_count = 1,
 678                .wpf_count = 1,
 679                .num_bru_inputs = 4,
 680                .uapi = true,
 681        }, {
 682                .version = VI6_IP_VERSION_MODEL_VSPS_M2,
 683                .model = "VSP1-S",
 684                .gen = 2,
 685                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
 686                          | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
 687                          | VSP1_HAS_WPF_VFLIP,
 688                .rpf_count = 5,
 689                .uds_count = 1,
 690                .wpf_count = 4,
 691                .num_bru_inputs = 4,
 692                .uapi = true,
 693        }, {
 694                .version = VI6_IP_VERSION_MODEL_VSPS_V2H,
 695                .model = "VSP1V-S",
 696                .gen = 2,
 697                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
 698                          | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
 699                .rpf_count = 4,
 700                .uds_count = 1,
 701                .wpf_count = 4,
 702                .num_bru_inputs = 4,
 703                .uapi = true,
 704        }, {
 705                .version = VI6_IP_VERSION_MODEL_VSPD_V2H,
 706                .model = "VSP1V-D",
 707                .gen = 2,
 708                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT,
 709                .lif_count = 1,
 710                .rpf_count = 4,
 711                .uds_count = 1,
 712                .wpf_count = 1,
 713                .num_bru_inputs = 4,
 714                .uapi = true,
 715        }, {
 716                .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
 717                .model = "VSP2-I",
 718                .gen = 3,
 719                .features = VSP1_HAS_CLU | VSP1_HAS_HGO | VSP1_HAS_HGT
 720                          | VSP1_HAS_LUT | VSP1_HAS_SRU | VSP1_HAS_WPF_HFLIP
 721                          | VSP1_HAS_WPF_VFLIP,
 722                .rpf_count = 1,
 723                .uds_count = 1,
 724                .wpf_count = 1,
 725                .uapi = true,
 726        }, {
 727                .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
 728                .model = "VSP2-BD",
 729                .gen = 3,
 730                .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
 731                .rpf_count = 5,
 732                .wpf_count = 1,
 733                .num_bru_inputs = 5,
 734                .uapi = true,
 735        }, {
 736                .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
 737                .model = "VSP2-BC",
 738                .gen = 3,
 739                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
 740                          | VSP1_HAS_LUT | VSP1_HAS_WPF_VFLIP,
 741                .rpf_count = 5,
 742                .wpf_count = 1,
 743                .num_bru_inputs = 5,
 744                .uapi = true,
 745        }, {
 746                .version = VI6_IP_VERSION_MODEL_VSPBS_GEN3,
 747                .model = "VSP2-BS",
 748                .gen = 3,
 749                .features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP,
 750                .rpf_count = 2,
 751                .wpf_count = 1,
 752                .uapi = true,
 753        }, {
 754                .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
 755                .model = "VSP2-D",
 756                .gen = 3,
 757                .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
 758                .lif_count = 1,
 759                .rpf_count = 5,
 760                .uif_count = 1,
 761                .wpf_count = 2,
 762                .num_bru_inputs = 5,
 763        }, {
 764                .version = VI6_IP_VERSION_MODEL_VSPD_V3,
 765                .model = "VSP2-D",
 766                .gen = 3,
 767                .features = VSP1_HAS_BRS | VSP1_HAS_BRU,
 768                .lif_count = 1,
 769                .rpf_count = 5,
 770                .uif_count = 1,
 771                .wpf_count = 1,
 772                .num_bru_inputs = 5,
 773        }, {
 774                .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3,
 775                .model = "VSP2-DL",
 776                .gen = 3,
 777                .features = VSP1_HAS_BRS | VSP1_HAS_BRU,
 778                .lif_count = 2,
 779                .rpf_count = 5,
 780                .uif_count = 2,
 781                .wpf_count = 2,
 782                .num_bru_inputs = 5,
 783        },
 784};
 785
 786static int vsp1_probe(struct platform_device *pdev)
 787{
 788        struct vsp1_device *vsp1;
 789        struct device_node *fcp_node;
 790        struct resource *irq;
 791        struct resource *io;
 792        unsigned int i;
 793        int ret;
 794
 795        vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
 796        if (vsp1 == NULL)
 797                return -ENOMEM;
 798
 799        vsp1->dev = &pdev->dev;
 800        INIT_LIST_HEAD(&vsp1->entities);
 801        INIT_LIST_HEAD(&vsp1->videos);
 802
 803        platform_set_drvdata(pdev, vsp1);
 804
 805        /* I/O and IRQ resources (clock managed by the clock PM domain) */
 806        io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 807        vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
 808        if (IS_ERR(vsp1->mmio))
 809                return PTR_ERR(vsp1->mmio);
 810
 811        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 812        if (!irq) {
 813                dev_err(&pdev->dev, "missing IRQ\n");
 814                return -EINVAL;
 815        }
 816
 817        ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
 818                              IRQF_SHARED, dev_name(&pdev->dev), vsp1);
 819        if (ret < 0) {
 820                dev_err(&pdev->dev, "failed to request IRQ\n");
 821                return ret;
 822        }
 823
 824        /* FCP (optional) */
 825        fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
 826        if (fcp_node) {
 827                vsp1->fcp = rcar_fcp_get(fcp_node);
 828                of_node_put(fcp_node);
 829                if (IS_ERR(vsp1->fcp)) {
 830                        dev_dbg(&pdev->dev, "FCP not found (%ld)\n",
 831                                PTR_ERR(vsp1->fcp));
 832                        return PTR_ERR(vsp1->fcp);
 833                }
 834
 835                /*
 836                 * When the FCP is present, it handles all bus master accesses
 837                 * for the VSP and must thus be used in place of the VSP device
 838                 * to map DMA buffers.
 839                 */
 840                vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp);
 841        } else {
 842                vsp1->bus_master = vsp1->dev;
 843        }
 844
 845        /* Configure device parameters based on the version register. */
 846        pm_runtime_enable(&pdev->dev);
 847
 848        ret = pm_runtime_get_sync(&pdev->dev);
 849        if (ret < 0)
 850                goto done;
 851
 852        vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
 853        pm_runtime_put_sync(&pdev->dev);
 854
 855        for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
 856                if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
 857                    vsp1_device_infos[i].version) {
 858                        vsp1->info = &vsp1_device_infos[i];
 859                        break;
 860                }
 861        }
 862
 863        if (!vsp1->info) {
 864                dev_err(&pdev->dev, "unsupported IP version 0x%08x\n",
 865                        vsp1->version);
 866                ret = -ENXIO;
 867                goto done;
 868        }
 869
 870        dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version);
 871
 872        /* Instanciate entities */
 873        ret = vsp1_create_entities(vsp1);
 874        if (ret < 0) {
 875                dev_err(&pdev->dev, "failed to create entities\n");
 876                goto done;
 877        }
 878
 879done:
 880        if (ret)
 881                pm_runtime_disable(&pdev->dev);
 882
 883        return ret;
 884}
 885
 886static int vsp1_remove(struct platform_device *pdev)
 887{
 888        struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
 889
 890        vsp1_destroy_entities(vsp1);
 891        rcar_fcp_put(vsp1->fcp);
 892
 893        pm_runtime_disable(&pdev->dev);
 894
 895        return 0;
 896}
 897
 898static const struct of_device_id vsp1_of_match[] = {
 899        { .compatible = "renesas,vsp1" },
 900        { .compatible = "renesas,vsp2" },
 901        { },
 902};
 903MODULE_DEVICE_TABLE(of, vsp1_of_match);
 904
 905static struct platform_driver vsp1_platform_driver = {
 906        .probe          = vsp1_probe,
 907        .remove         = vsp1_remove,
 908        .driver         = {
 909                .name   = "vsp1",
 910                .pm     = &vsp1_pm_ops,
 911                .of_match_table = vsp1_of_match,
 912        },
 913};
 914
 915module_platform_driver(vsp1_platform_driver);
 916
 917MODULE_ALIAS("vsp1");
 918MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 919MODULE_DESCRIPTION("Renesas VSP1 Driver");
 920MODULE_LICENSE("GPL");
 921