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_feature(vsp1, 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_feature(vsp1, 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_feature(vsp1, 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_feature(vsp1, 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_feature(vsp1, 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_feature(vsp1, 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_feature(vsp1, 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_feature(vsp1, 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        return pm_runtime_resume_and_get(vsp1->dev);
 563}
 564
 565/*
 566 * vsp1_device_put - Release the VSP1 device
 567 *
 568 * Decrement the VSP1 reference count and cleanup the device if the last
 569 * reference is released.
 570 */
 571void vsp1_device_put(struct vsp1_device *vsp1)
 572{
 573        pm_runtime_put_sync(vsp1->dev);
 574}
 575
 576/* -----------------------------------------------------------------------------
 577 * Power Management
 578 */
 579
 580static int __maybe_unused vsp1_pm_suspend(struct device *dev)
 581{
 582        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 583
 584        /*
 585         * When used as part of a display pipeline, the VSP is stopped and
 586         * restarted explicitly by the DU.
 587         */
 588        if (!vsp1->drm)
 589                vsp1_video_suspend(vsp1);
 590
 591        pm_runtime_force_suspend(vsp1->dev);
 592
 593        return 0;
 594}
 595
 596static int __maybe_unused vsp1_pm_resume(struct device *dev)
 597{
 598        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 599
 600        pm_runtime_force_resume(vsp1->dev);
 601
 602        /*
 603         * When used as part of a display pipeline, the VSP is stopped and
 604         * restarted explicitly by the DU.
 605         */
 606        if (!vsp1->drm)
 607                vsp1_video_resume(vsp1);
 608
 609        return 0;
 610}
 611
 612static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev)
 613{
 614        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 615
 616        rcar_fcp_disable(vsp1->fcp);
 617
 618        return 0;
 619}
 620
 621static int __maybe_unused vsp1_pm_runtime_resume(struct device *dev)
 622{
 623        struct vsp1_device *vsp1 = dev_get_drvdata(dev);
 624        int ret;
 625
 626        if (vsp1->info) {
 627                ret = vsp1_device_init(vsp1);
 628                if (ret < 0)
 629                        return ret;
 630        }
 631
 632        return rcar_fcp_enable(vsp1->fcp);
 633}
 634
 635static const struct dev_pm_ops vsp1_pm_ops = {
 636        SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
 637        SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL)
 638};
 639
 640/* -----------------------------------------------------------------------------
 641 * Platform Driver
 642 */
 643
 644static const struct vsp1_device_info vsp1_device_infos[] = {
 645        {
 646                .version = VI6_IP_VERSION_MODEL_VSPS_H2,
 647                .model = "VSP1-S",
 648                .gen = 2,
 649                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
 650                          | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
 651                          | VSP1_HAS_WPF_VFLIP,
 652                .rpf_count = 5,
 653                .uds_count = 3,
 654                .wpf_count = 4,
 655                .num_bru_inputs = 4,
 656                .uapi = true,
 657        }, {
 658                .version = VI6_IP_VERSION_MODEL_VSPR_H2,
 659                .model = "VSP1-R",
 660                .gen = 2,
 661                .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
 662                .rpf_count = 5,
 663                .uds_count = 3,
 664                .wpf_count = 4,
 665                .num_bru_inputs = 4,
 666                .uapi = true,
 667        }, {
 668                .version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
 669                .model = "VSP1-D",
 670                .gen = 2,
 671                .features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT,
 672                .lif_count = 1,
 673                .rpf_count = 4,
 674                .uds_count = 1,
 675                .wpf_count = 1,
 676                .num_bru_inputs = 4,
 677                .uapi = true,
 678        }, {
 679                .version = VI6_IP_VERSION_MODEL_VSPS_M2,
 680                .model = "VSP1-S",
 681                .gen = 2,
 682                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
 683                          | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
 684                          | VSP1_HAS_WPF_VFLIP,
 685                .rpf_count = 5,
 686                .uds_count = 1,
 687                .wpf_count = 4,
 688                .num_bru_inputs = 4,
 689                .uapi = true,
 690        }, {
 691                .version = VI6_IP_VERSION_MODEL_VSPS_V2H,
 692                .model = "VSP1V-S",
 693                .gen = 2,
 694                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
 695                          | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
 696                .rpf_count = 4,
 697                .uds_count = 1,
 698                .wpf_count = 4,
 699                .num_bru_inputs = 4,
 700                .uapi = true,
 701        }, {
 702                .version = VI6_IP_VERSION_MODEL_VSPD_V2H,
 703                .model = "VSP1V-D",
 704                .gen = 2,
 705                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT,
 706                .lif_count = 1,
 707                .rpf_count = 4,
 708                .uds_count = 1,
 709                .wpf_count = 1,
 710                .num_bru_inputs = 4,
 711                .uapi = true,
 712        }, {
 713                .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
 714                .model = "VSP2-I",
 715                .gen = 3,
 716                .features = VSP1_HAS_CLU | VSP1_HAS_HGO | VSP1_HAS_HGT
 717                          | VSP1_HAS_LUT | VSP1_HAS_SRU | VSP1_HAS_WPF_HFLIP
 718                          | VSP1_HAS_WPF_VFLIP,
 719                .rpf_count = 1,
 720                .uds_count = 1,
 721                .wpf_count = 1,
 722                .uapi = true,
 723        }, {
 724                .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
 725                .model = "VSP2-BD",
 726                .gen = 3,
 727                .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
 728                .rpf_count = 5,
 729                .wpf_count = 1,
 730                .num_bru_inputs = 5,
 731                .uapi = true,
 732        }, {
 733                .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
 734                .model = "VSP2-BC",
 735                .gen = 3,
 736                .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
 737                          | VSP1_HAS_LUT | VSP1_HAS_WPF_VFLIP,
 738                .rpf_count = 5,
 739                .wpf_count = 1,
 740                .num_bru_inputs = 5,
 741                .uapi = true,
 742        }, {
 743                .version = VI6_IP_VERSION_MODEL_VSPBS_GEN3,
 744                .model = "VSP2-BS",
 745                .gen = 3,
 746                .features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP,
 747                .rpf_count = 2,
 748                .wpf_count = 1,
 749                .uapi = true,
 750        }, {
 751                .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
 752                .model = "VSP2-D",
 753                .gen = 3,
 754                .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP | VSP1_HAS_EXT_DL,
 755                .lif_count = 1,
 756                .rpf_count = 5,
 757                .uif_count = 1,
 758                .wpf_count = 2,
 759                .num_bru_inputs = 5,
 760        }, {
 761                .version = VI6_IP_VERSION_MODEL_VSPD_V3,
 762                .model = "VSP2-D",
 763                .gen = 3,
 764                .features = VSP1_HAS_BRS | VSP1_HAS_BRU,
 765                .lif_count = 1,
 766                .rpf_count = 5,
 767                .uif_count = 1,
 768                .wpf_count = 1,
 769                .num_bru_inputs = 5,
 770        }, {
 771                .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3,
 772                .model = "VSP2-DL",
 773                .gen = 3,
 774                .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_EXT_DL,
 775                .lif_count = 2,
 776                .rpf_count = 5,
 777                .uif_count = 2,
 778                .wpf_count = 2,
 779                .num_bru_inputs = 5,
 780        },
 781};
 782
 783static int vsp1_probe(struct platform_device *pdev)
 784{
 785        struct vsp1_device *vsp1;
 786        struct device_node *fcp_node;
 787        struct resource *irq;
 788        struct resource *io;
 789        unsigned int i;
 790        int ret;
 791
 792        vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
 793        if (vsp1 == NULL)
 794                return -ENOMEM;
 795
 796        vsp1->dev = &pdev->dev;
 797        INIT_LIST_HEAD(&vsp1->entities);
 798        INIT_LIST_HEAD(&vsp1->videos);
 799
 800        platform_set_drvdata(pdev, vsp1);
 801
 802        /* I/O and IRQ resources (clock managed by the clock PM domain). */
 803        io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 804        vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
 805        if (IS_ERR(vsp1->mmio))
 806                return PTR_ERR(vsp1->mmio);
 807
 808        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 809        if (!irq) {
 810                dev_err(&pdev->dev, "missing IRQ\n");
 811                return -EINVAL;
 812        }
 813
 814        ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
 815                              IRQF_SHARED, dev_name(&pdev->dev), vsp1);
 816        if (ret < 0) {
 817                dev_err(&pdev->dev, "failed to request IRQ\n");
 818                return ret;
 819        }
 820
 821        /* FCP (optional). */
 822        fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
 823        if (fcp_node) {
 824                vsp1->fcp = rcar_fcp_get(fcp_node);
 825                of_node_put(fcp_node);
 826                if (IS_ERR(vsp1->fcp)) {
 827                        dev_dbg(&pdev->dev, "FCP not found (%ld)\n",
 828                                PTR_ERR(vsp1->fcp));
 829                        return PTR_ERR(vsp1->fcp);
 830                }
 831
 832                /*
 833                 * When the FCP is present, it handles all bus master accesses
 834                 * for the VSP and must thus be used in place of the VSP device
 835                 * to map DMA buffers.
 836                 */
 837                vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp);
 838        } else {
 839                vsp1->bus_master = vsp1->dev;
 840        }
 841
 842        /* Configure device parameters based on the version register. */
 843        pm_runtime_enable(&pdev->dev);
 844
 845        ret = vsp1_device_get(vsp1);
 846        if (ret < 0)
 847                goto done;
 848
 849        vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
 850        vsp1_device_put(vsp1);
 851
 852        for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
 853                if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
 854                    vsp1_device_infos[i].version) {
 855                        vsp1->info = &vsp1_device_infos[i];
 856                        break;
 857                }
 858        }
 859
 860        if (!vsp1->info) {
 861                dev_err(&pdev->dev, "unsupported IP version 0x%08x\n",
 862                        vsp1->version);
 863                ret = -ENXIO;
 864                goto done;
 865        }
 866
 867        dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version);
 868
 869        /* Instantiate entities. */
 870        ret = vsp1_create_entities(vsp1);
 871        if (ret < 0) {
 872                dev_err(&pdev->dev, "failed to create entities\n");
 873                goto done;
 874        }
 875
 876done:
 877        if (ret) {
 878                pm_runtime_disable(&pdev->dev);
 879                rcar_fcp_put(vsp1->fcp);
 880        }
 881
 882        return ret;
 883}
 884
 885static int vsp1_remove(struct platform_device *pdev)
 886{
 887        struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
 888
 889        vsp1_destroy_entities(vsp1);
 890        rcar_fcp_put(vsp1->fcp);
 891
 892        pm_runtime_disable(&pdev->dev);
 893
 894        return 0;
 895}
 896
 897static const struct of_device_id vsp1_of_match[] = {
 898        { .compatible = "renesas,vsp1" },
 899        { .compatible = "renesas,vsp2" },
 900        { },
 901};
 902MODULE_DEVICE_TABLE(of, vsp1_of_match);
 903
 904static struct platform_driver vsp1_platform_driver = {
 905        .probe          = vsp1_probe,
 906        .remove         = vsp1_remove,
 907        .driver         = {
 908                .name   = "vsp1",
 909                .pm     = &vsp1_pm_ops,
 910                .of_match_table = vsp1_of_match,
 911        },
 912};
 913
 914module_platform_driver(vsp1_platform_driver);
 915
 916MODULE_ALIAS("vsp1");
 917MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
 918MODULE_DESCRIPTION("Renesas VSP1 Driver");
 919MODULE_LICENSE("GPL");
 920