cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vsp1_drv.c (22389B)


      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_WPF_IRQ_STA_DFE | VI6_WPF_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_WPF_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	media_device_init(mdev);
    247
    248	vsp1->media_ops.link_setup = vsp1_entity_link_setup;
    249	/*
    250	 * Don't perform link validation when the userspace API is disabled as
    251	 * the pipeline is configured internally by the driver in that case, and
    252	 * its configuration can thus be trusted.
    253	 */
    254	if (vsp1->info->uapi)
    255		vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
    256
    257	vdev->mdev = mdev;
    258	ret = v4l2_device_register(vsp1->dev, vdev);
    259	if (ret < 0) {
    260		dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
    261			ret);
    262		goto done;
    263	}
    264
    265	/* Instantiate all the entities. */
    266	if (vsp1_feature(vsp1, VSP1_HAS_BRS)) {
    267		vsp1->brs = vsp1_brx_create(vsp1, VSP1_ENTITY_BRS);
    268		if (IS_ERR(vsp1->brs)) {
    269			ret = PTR_ERR(vsp1->brs);
    270			goto done;
    271		}
    272
    273		list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities);
    274	}
    275
    276	if (vsp1_feature(vsp1, VSP1_HAS_BRU)) {
    277		vsp1->bru = vsp1_brx_create(vsp1, VSP1_ENTITY_BRU);
    278		if (IS_ERR(vsp1->bru)) {
    279			ret = PTR_ERR(vsp1->bru);
    280			goto done;
    281		}
    282
    283		list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
    284	}
    285
    286	if (vsp1_feature(vsp1, VSP1_HAS_CLU)) {
    287		vsp1->clu = vsp1_clu_create(vsp1);
    288		if (IS_ERR(vsp1->clu)) {
    289			ret = PTR_ERR(vsp1->clu);
    290			goto done;
    291		}
    292
    293		list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities);
    294	}
    295
    296	vsp1->hsi = vsp1_hsit_create(vsp1, true);
    297	if (IS_ERR(vsp1->hsi)) {
    298		ret = PTR_ERR(vsp1->hsi);
    299		goto done;
    300	}
    301
    302	list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
    303
    304	vsp1->hst = vsp1_hsit_create(vsp1, false);
    305	if (IS_ERR(vsp1->hst)) {
    306		ret = PTR_ERR(vsp1->hst);
    307		goto done;
    308	}
    309
    310	list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
    311
    312	if (vsp1_feature(vsp1, VSP1_HAS_HGO) && vsp1->info->uapi) {
    313		vsp1->hgo = vsp1_hgo_create(vsp1);
    314		if (IS_ERR(vsp1->hgo)) {
    315			ret = PTR_ERR(vsp1->hgo);
    316			goto done;
    317		}
    318
    319		list_add_tail(&vsp1->hgo->histo.entity.list_dev,
    320			      &vsp1->entities);
    321	}
    322
    323	if (vsp1_feature(vsp1, VSP1_HAS_HGT) && vsp1->info->uapi) {
    324		vsp1->hgt = vsp1_hgt_create(vsp1);
    325		if (IS_ERR(vsp1->hgt)) {
    326			ret = PTR_ERR(vsp1->hgt);
    327			goto done;
    328		}
    329
    330		list_add_tail(&vsp1->hgt->histo.entity.list_dev,
    331			      &vsp1->entities);
    332	}
    333
    334	/*
    335	 * The LIFs are only supported when used in conjunction with the DU, in
    336	 * which case the userspace API is disabled. If the userspace API is
    337	 * enabled skip the LIFs, even when present.
    338	 */
    339	if (!vsp1->info->uapi) {
    340		for (i = 0; i < vsp1->info->lif_count; ++i) {
    341			struct vsp1_lif *lif;
    342
    343			lif = vsp1_lif_create(vsp1, i);
    344			if (IS_ERR(lif)) {
    345				ret = PTR_ERR(lif);
    346				goto done;
    347			}
    348
    349			vsp1->lif[i] = lif;
    350			list_add_tail(&lif->entity.list_dev, &vsp1->entities);
    351		}
    352	}
    353
    354	if (vsp1_feature(vsp1, VSP1_HAS_LUT)) {
    355		vsp1->lut = vsp1_lut_create(vsp1);
    356		if (IS_ERR(vsp1->lut)) {
    357			ret = PTR_ERR(vsp1->lut);
    358			goto done;
    359		}
    360
    361		list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
    362	}
    363
    364	for (i = 0; i < vsp1->info->rpf_count; ++i) {
    365		struct vsp1_rwpf *rpf;
    366
    367		rpf = vsp1_rpf_create(vsp1, i);
    368		if (IS_ERR(rpf)) {
    369			ret = PTR_ERR(rpf);
    370			goto done;
    371		}
    372
    373		vsp1->rpf[i] = rpf;
    374		list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
    375
    376		if (vsp1->info->uapi) {
    377			struct vsp1_video *video = vsp1_video_create(vsp1, rpf);
    378
    379			if (IS_ERR(video)) {
    380				ret = PTR_ERR(video);
    381				goto done;
    382			}
    383
    384			list_add_tail(&video->list, &vsp1->videos);
    385		}
    386	}
    387
    388	if (vsp1_feature(vsp1, VSP1_HAS_SRU)) {
    389		vsp1->sru = vsp1_sru_create(vsp1);
    390		if (IS_ERR(vsp1->sru)) {
    391			ret = PTR_ERR(vsp1->sru);
    392			goto done;
    393		}
    394
    395		list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
    396	}
    397
    398	for (i = 0; i < vsp1->info->uds_count; ++i) {
    399		struct vsp1_uds *uds;
    400
    401		uds = vsp1_uds_create(vsp1, i);
    402		if (IS_ERR(uds)) {
    403			ret = PTR_ERR(uds);
    404			goto done;
    405		}
    406
    407		vsp1->uds[i] = uds;
    408		list_add_tail(&uds->entity.list_dev, &vsp1->entities);
    409	}
    410
    411	for (i = 0; i < vsp1->info->uif_count; ++i) {
    412		struct vsp1_uif *uif;
    413
    414		uif = vsp1_uif_create(vsp1, i);
    415		if (IS_ERR(uif)) {
    416			ret = PTR_ERR(uif);
    417			goto done;
    418		}
    419
    420		vsp1->uif[i] = uif;
    421		list_add_tail(&uif->entity.list_dev, &vsp1->entities);
    422	}
    423
    424	for (i = 0; i < vsp1->info->wpf_count; ++i) {
    425		struct vsp1_rwpf *wpf;
    426
    427		wpf = vsp1_wpf_create(vsp1, i);
    428		if (IS_ERR(wpf)) {
    429			ret = PTR_ERR(wpf);
    430			goto done;
    431		}
    432
    433		vsp1->wpf[i] = wpf;
    434		list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
    435
    436		if (vsp1->info->uapi) {
    437			struct vsp1_video *video = vsp1_video_create(vsp1, wpf);
    438
    439			if (IS_ERR(video)) {
    440				ret = PTR_ERR(video);
    441				goto done;
    442			}
    443
    444			list_add_tail(&video->list, &vsp1->videos);
    445		}
    446	}
    447
    448	/* Register all subdevs. */
    449	list_for_each_entry(entity, &vsp1->entities, list_dev) {
    450		ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
    451						  &entity->subdev);
    452		if (ret < 0)
    453			goto done;
    454	}
    455
    456	/*
    457	 * Create links and register subdev nodes if the userspace API is
    458	 * enabled or initialize the DRM pipeline otherwise.
    459	 */
    460	if (vsp1->info->uapi) {
    461		ret = vsp1_uapi_create_links(vsp1);
    462		if (ret < 0)
    463			goto done;
    464
    465		ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
    466		if (ret < 0)
    467			goto done;
    468
    469		ret = media_device_register(mdev);
    470	} else {
    471		ret = vsp1_drm_init(vsp1);
    472	}
    473
    474done:
    475	if (ret < 0)
    476		vsp1_destroy_entities(vsp1);
    477
    478	return ret;
    479}
    480
    481int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
    482{
    483	unsigned int timeout;
    484	u32 status;
    485
    486	status = vsp1_read(vsp1, VI6_STATUS);
    487	if (!(status & VI6_STATUS_SYS_ACT(index)))
    488		return 0;
    489
    490	vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
    491	for (timeout = 10; timeout > 0; --timeout) {
    492		status = vsp1_read(vsp1, VI6_STATUS);
    493		if (!(status & VI6_STATUS_SYS_ACT(index)))
    494			break;
    495
    496		usleep_range(1000, 2000);
    497	}
    498
    499	if (!timeout) {
    500		dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
    501		return -ETIMEDOUT;
    502	}
    503
    504	return 0;
    505}
    506
    507static int vsp1_device_init(struct vsp1_device *vsp1)
    508{
    509	unsigned int i;
    510	int ret;
    511
    512	/* Reset any channel that might be running. */
    513	for (i = 0; i < vsp1->info->wpf_count; ++i) {
    514		ret = vsp1_reset_wpf(vsp1, i);
    515		if (ret < 0)
    516			return ret;
    517	}
    518
    519	vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
    520		   (8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
    521
    522	for (i = 0; i < vsp1->info->rpf_count; ++i)
    523		vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
    524
    525	for (i = 0; i < vsp1->info->uds_count; ++i)
    526		vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
    527
    528	for (i = 0; i < vsp1->info->uif_count; ++i)
    529		vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED);
    530
    531	vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
    532	vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
    533	vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
    534	vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
    535	vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
    536	vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
    537
    538	if (vsp1_feature(vsp1, VSP1_HAS_BRS))
    539		vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED);
    540
    541	vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
    542		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
    543	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
    544		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
    545
    546	vsp1_dlm_setup(vsp1);
    547
    548	return 0;
    549}
    550
    551static void vsp1_mask_all_interrupts(struct vsp1_device *vsp1)
    552{
    553	unsigned int i;
    554
    555	for (i = 0; i < vsp1->info->lif_count; ++i)
    556		vsp1_write(vsp1, VI6_DISP_IRQ_ENB(i), 0);
    557	for (i = 0; i < vsp1->info->wpf_count; ++i)
    558		vsp1_write(vsp1, VI6_WPF_IRQ_ENB(i), 0);
    559}
    560
    561/*
    562 * vsp1_device_get - Acquire the VSP1 device
    563 *
    564 * Make sure the device is not suspended and initialize it if needed.
    565 *
    566 * Return 0 on success or a negative error code otherwise.
    567 */
    568int vsp1_device_get(struct vsp1_device *vsp1)
    569{
    570	return pm_runtime_resume_and_get(vsp1->dev);
    571}
    572
    573/*
    574 * vsp1_device_put - Release the VSP1 device
    575 *
    576 * Decrement the VSP1 reference count and cleanup the device if the last
    577 * reference is released.
    578 */
    579void vsp1_device_put(struct vsp1_device *vsp1)
    580{
    581	pm_runtime_put_sync(vsp1->dev);
    582}
    583
    584/* -----------------------------------------------------------------------------
    585 * Power Management
    586 */
    587
    588static int __maybe_unused vsp1_pm_suspend(struct device *dev)
    589{
    590	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
    591
    592	/*
    593	 * When used as part of a display pipeline, the VSP is stopped and
    594	 * restarted explicitly by the DU.
    595	 */
    596	if (!vsp1->drm)
    597		vsp1_video_suspend(vsp1);
    598
    599	pm_runtime_force_suspend(vsp1->dev);
    600
    601	return 0;
    602}
    603
    604static int __maybe_unused vsp1_pm_resume(struct device *dev)
    605{
    606	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
    607
    608	pm_runtime_force_resume(vsp1->dev);
    609
    610	/*
    611	 * When used as part of a display pipeline, the VSP is stopped and
    612	 * restarted explicitly by the DU.
    613	 */
    614	if (!vsp1->drm)
    615		vsp1_video_resume(vsp1);
    616
    617	return 0;
    618}
    619
    620static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev)
    621{
    622	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
    623
    624	rcar_fcp_disable(vsp1->fcp);
    625
    626	return 0;
    627}
    628
    629static int __maybe_unused vsp1_pm_runtime_resume(struct device *dev)
    630{
    631	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
    632	int ret;
    633
    634	if (vsp1->info) {
    635		ret = vsp1_device_init(vsp1);
    636		if (ret < 0)
    637			return ret;
    638	}
    639
    640	return rcar_fcp_enable(vsp1->fcp);
    641}
    642
    643static const struct dev_pm_ops vsp1_pm_ops = {
    644	SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
    645	SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL)
    646};
    647
    648/* -----------------------------------------------------------------------------
    649 * Platform Driver
    650 */
    651
    652static const struct vsp1_device_info vsp1_device_infos[] = {
    653	{
    654		.version = VI6_IP_VERSION_MODEL_VSPS_H2,
    655		.model = "VSP1-S",
    656		.gen = 2,
    657		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
    658			  | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
    659			  | VSP1_HAS_WPF_VFLIP,
    660		.rpf_count = 5,
    661		.uds_count = 3,
    662		.wpf_count = 4,
    663		.num_bru_inputs = 4,
    664		.uapi = true,
    665	}, {
    666		.version = VI6_IP_VERSION_MODEL_VSPR_H2,
    667		.model = "VSP1-R",
    668		.gen = 2,
    669		.features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
    670		.rpf_count = 5,
    671		.uds_count = 3,
    672		.wpf_count = 4,
    673		.num_bru_inputs = 4,
    674		.uapi = true,
    675	}, {
    676		.version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
    677		.model = "VSP1-D",
    678		.gen = 2,
    679		.features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT,
    680		.lif_count = 1,
    681		.rpf_count = 4,
    682		.uds_count = 1,
    683		.wpf_count = 1,
    684		.num_bru_inputs = 4,
    685		.uapi = true,
    686	}, {
    687		.version = VI6_IP_VERSION_MODEL_VSPS_M2,
    688		.model = "VSP1-S",
    689		.gen = 2,
    690		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
    691			  | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
    692			  | VSP1_HAS_WPF_VFLIP,
    693		.rpf_count = 5,
    694		.uds_count = 1,
    695		.wpf_count = 4,
    696		.num_bru_inputs = 4,
    697		.uapi = true,
    698	}, {
    699		.version = VI6_IP_VERSION_MODEL_VSPS_V2H,
    700		.model = "VSP1V-S",
    701		.gen = 2,
    702		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
    703			  | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
    704		.rpf_count = 4,
    705		.uds_count = 1,
    706		.wpf_count = 4,
    707		.num_bru_inputs = 4,
    708		.uapi = true,
    709	}, {
    710		.version = VI6_IP_VERSION_MODEL_VSPD_V2H,
    711		.model = "VSP1V-D",
    712		.gen = 2,
    713		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT,
    714		.lif_count = 1,
    715		.rpf_count = 4,
    716		.uds_count = 1,
    717		.wpf_count = 1,
    718		.num_bru_inputs = 4,
    719		.uapi = true,
    720	}, {
    721		.version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
    722		.model = "VSP2-I",
    723		.gen = 3,
    724		.features = VSP1_HAS_CLU | VSP1_HAS_HGO | VSP1_HAS_HGT
    725			  | VSP1_HAS_LUT | VSP1_HAS_SRU | VSP1_HAS_WPF_HFLIP
    726			  | VSP1_HAS_WPF_VFLIP,
    727		.rpf_count = 1,
    728		.uds_count = 1,
    729		.wpf_count = 1,
    730		.uapi = true,
    731	}, {
    732		.version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
    733		.model = "VSP2-BD",
    734		.gen = 3,
    735		.features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
    736		.rpf_count = 5,
    737		.wpf_count = 1,
    738		.num_bru_inputs = 5,
    739		.uapi = true,
    740	}, {
    741		.version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
    742		.model = "VSP2-BC",
    743		.gen = 3,
    744		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
    745			  | VSP1_HAS_LUT | VSP1_HAS_WPF_VFLIP,
    746		.rpf_count = 5,
    747		.wpf_count = 1,
    748		.num_bru_inputs = 5,
    749		.uapi = true,
    750	}, {
    751		.version = VI6_IP_VERSION_MODEL_VSPBS_GEN3,
    752		.model = "VSP2-BS",
    753		.gen = 3,
    754		.features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP,
    755		.rpf_count = 2,
    756		.wpf_count = 1,
    757		.uapi = true,
    758	}, {
    759		.version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
    760		.model = "VSP2-D",
    761		.gen = 3,
    762		.features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP | VSP1_HAS_EXT_DL,
    763		.lif_count = 1,
    764		.rpf_count = 5,
    765		.uif_count = 1,
    766		.wpf_count = 2,
    767		.num_bru_inputs = 5,
    768	}, {
    769		.version = VI6_IP_VERSION_MODEL_VSPD_V3,
    770		.model = "VSP2-D",
    771		.gen = 3,
    772		.features = VSP1_HAS_BRS | VSP1_HAS_BRU,
    773		.lif_count = 1,
    774		.rpf_count = 5,
    775		.uif_count = 1,
    776		.wpf_count = 1,
    777		.num_bru_inputs = 5,
    778	}, {
    779		.version = VI6_IP_VERSION_MODEL_VSPDL_GEN3,
    780		.model = "VSP2-DL",
    781		.gen = 3,
    782		.features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_EXT_DL,
    783		.lif_count = 2,
    784		.rpf_count = 5,
    785		.uif_count = 2,
    786		.wpf_count = 2,
    787		.num_bru_inputs = 5,
    788	}, {
    789		.version = VI6_IP_VERSION_MODEL_VSPD_V3U,
    790		.model = "VSP2-D",
    791		.gen = 3,
    792		.features = VSP1_HAS_BRU | VSP1_HAS_EXT_DL,
    793		.lif_count = 1,
    794		.rpf_count = 5,
    795		.uif_count = 2,
    796		.wpf_count = 1,
    797		.num_bru_inputs = 5,
    798	},
    799};
    800
    801static int vsp1_probe(struct platform_device *pdev)
    802{
    803	struct vsp1_device *vsp1;
    804	struct device_node *fcp_node;
    805	unsigned int i;
    806	int ret;
    807	int irq;
    808
    809	vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
    810	if (vsp1 == NULL)
    811		return -ENOMEM;
    812
    813	vsp1->dev = &pdev->dev;
    814	INIT_LIST_HEAD(&vsp1->entities);
    815	INIT_LIST_HEAD(&vsp1->videos);
    816
    817	platform_set_drvdata(pdev, vsp1);
    818
    819	/* I/O and IRQ resources (clock managed by the clock PM domain). */
    820	vsp1->mmio = devm_platform_ioremap_resource(pdev, 0);
    821	if (IS_ERR(vsp1->mmio))
    822		return PTR_ERR(vsp1->mmio);
    823
    824	irq = platform_get_irq(pdev, 0);
    825	if (irq < 0)
    826		return irq;
    827
    828	/* FCP (optional). */
    829	fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
    830	if (fcp_node) {
    831		vsp1->fcp = rcar_fcp_get(fcp_node);
    832		of_node_put(fcp_node);
    833		if (IS_ERR(vsp1->fcp)) {
    834			dev_dbg(&pdev->dev, "FCP not found (%ld)\n",
    835				PTR_ERR(vsp1->fcp));
    836			return PTR_ERR(vsp1->fcp);
    837		}
    838
    839		/*
    840		 * When the FCP is present, it handles all bus master accesses
    841		 * for the VSP and must thus be used in place of the VSP device
    842		 * to map DMA buffers.
    843		 */
    844		vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp);
    845	} else {
    846		vsp1->bus_master = vsp1->dev;
    847	}
    848
    849	/* Configure device parameters based on the version register. */
    850	pm_runtime_enable(&pdev->dev);
    851
    852	ret = vsp1_device_get(vsp1);
    853	if (ret < 0)
    854		goto done;
    855
    856	vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
    857
    858	for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
    859		if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
    860		    vsp1_device_infos[i].version) {
    861			vsp1->info = &vsp1_device_infos[i];
    862			break;
    863		}
    864	}
    865
    866	if (!vsp1->info) {
    867		dev_err(&pdev->dev, "unsupported IP version 0x%08x\n",
    868			vsp1->version);
    869		vsp1_device_put(vsp1);
    870		ret = -ENXIO;
    871		goto done;
    872	}
    873
    874	dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version);
    875
    876	/*
    877	 * Previous use of the hardware (e.g. by the bootloader) could leave
    878	 * some interrupts enabled and pending.
    879	 *
    880	 * TODO: Investigate if this shouldn't be better handled by using the
    881	 * device reset provided by the CPG.
    882	 */
    883	vsp1_mask_all_interrupts(vsp1);
    884
    885	vsp1_device_put(vsp1);
    886
    887	ret = devm_request_irq(&pdev->dev, irq, vsp1_irq_handler,
    888			       IRQF_SHARED, dev_name(&pdev->dev), vsp1);
    889	if (ret < 0) {
    890		dev_err(&pdev->dev, "failed to request IRQ\n");
    891		goto done;
    892	}
    893
    894	/* Instantiate entities. */
    895	ret = vsp1_create_entities(vsp1);
    896	if (ret < 0) {
    897		dev_err(&pdev->dev, "failed to create entities\n");
    898		goto done;
    899	}
    900
    901done:
    902	if (ret) {
    903		pm_runtime_disable(&pdev->dev);
    904		rcar_fcp_put(vsp1->fcp);
    905	}
    906
    907	return ret;
    908}
    909
    910static int vsp1_remove(struct platform_device *pdev)
    911{
    912	struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
    913
    914	vsp1_destroy_entities(vsp1);
    915	rcar_fcp_put(vsp1->fcp);
    916
    917	pm_runtime_disable(&pdev->dev);
    918
    919	return 0;
    920}
    921
    922static const struct of_device_id vsp1_of_match[] = {
    923	{ .compatible = "renesas,vsp1" },
    924	{ .compatible = "renesas,vsp2" },
    925	{ },
    926};
    927MODULE_DEVICE_TABLE(of, vsp1_of_match);
    928
    929static struct platform_driver vsp1_platform_driver = {
    930	.probe		= vsp1_probe,
    931	.remove		= vsp1_remove,
    932	.driver		= {
    933		.name	= "vsp1",
    934		.pm	= &vsp1_pm_ops,
    935		.of_match_table = vsp1_of_match,
    936	},
    937};
    938
    939module_platform_driver(vsp1_platform_driver);
    940
    941MODULE_ALIAS("vsp1");
    942MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
    943MODULE_DESCRIPTION("Renesas VSP1 Driver");
    944MODULE_LICENSE("GPL");