18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * vsp1_drv.c  --  R-Car VSP1 Driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013-2015 Renesas Electronics Corporation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/of_device.h>
178c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
198c2ecf20Sopenharmony_ci#include <linux/videodev2.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <media/rcar-fcp.h>
228c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "vsp1.h"
258c2ecf20Sopenharmony_ci#include "vsp1_brx.h"
268c2ecf20Sopenharmony_ci#include "vsp1_clu.h"
278c2ecf20Sopenharmony_ci#include "vsp1_dl.h"
288c2ecf20Sopenharmony_ci#include "vsp1_drm.h"
298c2ecf20Sopenharmony_ci#include "vsp1_hgo.h"
308c2ecf20Sopenharmony_ci#include "vsp1_hgt.h"
318c2ecf20Sopenharmony_ci#include "vsp1_hsit.h"
328c2ecf20Sopenharmony_ci#include "vsp1_lif.h"
338c2ecf20Sopenharmony_ci#include "vsp1_lut.h"
348c2ecf20Sopenharmony_ci#include "vsp1_pipe.h"
358c2ecf20Sopenharmony_ci#include "vsp1_rwpf.h"
368c2ecf20Sopenharmony_ci#include "vsp1_sru.h"
378c2ecf20Sopenharmony_ci#include "vsp1_uds.h"
388c2ecf20Sopenharmony_ci#include "vsp1_uif.h"
398c2ecf20Sopenharmony_ci#include "vsp1_video.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
428c2ecf20Sopenharmony_ci * Interrupt Handling
438c2ecf20Sopenharmony_ci */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic irqreturn_t vsp1_irq_handler(int irq, void *data)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
488c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1 = data;
498c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
508c2ecf20Sopenharmony_ci	unsigned int i;
518c2ecf20Sopenharmony_ci	u32 status;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->wpf_count; ++i) {
548c2ecf20Sopenharmony_ci		struct vsp1_rwpf *wpf = vsp1->wpf[i];
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		if (wpf == NULL)
578c2ecf20Sopenharmony_ci			continue;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
608c2ecf20Sopenharmony_ci		vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		if (status & VI6_WFP_IRQ_STA_DFE) {
638c2ecf20Sopenharmony_ci			vsp1_pipeline_frame_end(wpf->entity.pipe);
648c2ecf20Sopenharmony_ci			ret = IRQ_HANDLED;
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return ret;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
728c2ecf20Sopenharmony_ci * Entities
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/*
768c2ecf20Sopenharmony_ci * vsp1_create_sink_links - Create links from all sources to the given sink
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * This function creates media links from all valid sources to the given sink
798c2ecf20Sopenharmony_ci * pad. Links that would be invalid according to the VSP1 hardware capabilities
808c2ecf20Sopenharmony_ci * are skipped. Those include all links
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * - from a UDS to a UDS (UDS entities can't be chained)
838c2ecf20Sopenharmony_ci * - from an entity to itself (no loops are allowed)
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci * Furthermore, the BRS can't be connected to histogram generators, but no
868c2ecf20Sopenharmony_ci * special check is currently needed as all VSP instances that include a BRS
878c2ecf20Sopenharmony_ci * have no histogram generator.
888c2ecf20Sopenharmony_ci */
898c2ecf20Sopenharmony_cistatic int vsp1_create_sink_links(struct vsp1_device *vsp1,
908c2ecf20Sopenharmony_ci				  struct vsp1_entity *sink)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct media_entity *entity = &sink->subdev.entity;
938c2ecf20Sopenharmony_ci	struct vsp1_entity *source;
948c2ecf20Sopenharmony_ci	unsigned int pad;
958c2ecf20Sopenharmony_ci	int ret;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	list_for_each_entry(source, &vsp1->entities, list_dev) {
988c2ecf20Sopenharmony_ci		u32 flags;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		if (source->type == sink->type)
1018c2ecf20Sopenharmony_ci			continue;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		if (source->type == VSP1_ENTITY_HGO ||
1048c2ecf20Sopenharmony_ci		    source->type == VSP1_ENTITY_HGT ||
1058c2ecf20Sopenharmony_ci		    source->type == VSP1_ENTITY_LIF ||
1068c2ecf20Sopenharmony_ci		    source->type == VSP1_ENTITY_WPF)
1078c2ecf20Sopenharmony_ci			continue;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		flags = source->type == VSP1_ENTITY_RPF &&
1108c2ecf20Sopenharmony_ci			sink->type == VSP1_ENTITY_WPF &&
1118c2ecf20Sopenharmony_ci			source->index == sink->index
1128c2ecf20Sopenharmony_ci		      ? MEDIA_LNK_FL_ENABLED : 0;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		for (pad = 0; pad < entity->num_pads; ++pad) {
1158c2ecf20Sopenharmony_ci			if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
1168c2ecf20Sopenharmony_ci				continue;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci			ret = media_create_pad_link(&source->subdev.entity,
1198c2ecf20Sopenharmony_ci						       source->source_pad,
1208c2ecf20Sopenharmony_ci						       entity, pad, flags);
1218c2ecf20Sopenharmony_ci			if (ret < 0)
1228c2ecf20Sopenharmony_ci				return ret;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci			if (flags & MEDIA_LNK_FL_ENABLED)
1258c2ecf20Sopenharmony_ci				source->sink = sink;
1268c2ecf20Sopenharmony_ci		}
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int vsp1_uapi_create_links(struct vsp1_device *vsp1)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct vsp1_entity *entity;
1358c2ecf20Sopenharmony_ci	unsigned int i;
1368c2ecf20Sopenharmony_ci	int ret;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	list_for_each_entry(entity, &vsp1->entities, list_dev) {
1398c2ecf20Sopenharmony_ci		if (entity->type == VSP1_ENTITY_LIF ||
1408c2ecf20Sopenharmony_ci		    entity->type == VSP1_ENTITY_RPF)
1418c2ecf20Sopenharmony_ci			continue;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci		ret = vsp1_create_sink_links(vsp1, entity);
1448c2ecf20Sopenharmony_ci		if (ret < 0)
1458c2ecf20Sopenharmony_ci			return ret;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (vsp1->hgo) {
1498c2ecf20Sopenharmony_ci		ret = media_create_pad_link(&vsp1->hgo->histo.entity.subdev.entity,
1508c2ecf20Sopenharmony_ci					    HISTO_PAD_SOURCE,
1518c2ecf20Sopenharmony_ci					    &vsp1->hgo->histo.video.entity, 0,
1528c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED |
1538c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_IMMUTABLE);
1548c2ecf20Sopenharmony_ci		if (ret < 0)
1558c2ecf20Sopenharmony_ci			return ret;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (vsp1->hgt) {
1598c2ecf20Sopenharmony_ci		ret = media_create_pad_link(&vsp1->hgt->histo.entity.subdev.entity,
1608c2ecf20Sopenharmony_ci					    HISTO_PAD_SOURCE,
1618c2ecf20Sopenharmony_ci					    &vsp1->hgt->histo.video.entity, 0,
1628c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED |
1638c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_IMMUTABLE);
1648c2ecf20Sopenharmony_ci		if (ret < 0)
1658c2ecf20Sopenharmony_ci			return ret;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->lif_count; ++i) {
1698c2ecf20Sopenharmony_ci		if (!vsp1->lif[i])
1708c2ecf20Sopenharmony_ci			continue;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci		ret = media_create_pad_link(&vsp1->wpf[i]->entity.subdev.entity,
1738c2ecf20Sopenharmony_ci					    RWPF_PAD_SOURCE,
1748c2ecf20Sopenharmony_ci					    &vsp1->lif[i]->entity.subdev.entity,
1758c2ecf20Sopenharmony_ci					    LIF_PAD_SINK, 0);
1768c2ecf20Sopenharmony_ci		if (ret < 0)
1778c2ecf20Sopenharmony_ci			return ret;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->rpf_count; ++i) {
1818c2ecf20Sopenharmony_ci		struct vsp1_rwpf *rpf = vsp1->rpf[i];
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci		ret = media_create_pad_link(&rpf->video->video.entity, 0,
1848c2ecf20Sopenharmony_ci					    &rpf->entity.subdev.entity,
1858c2ecf20Sopenharmony_ci					    RWPF_PAD_SINK,
1868c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED |
1878c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_IMMUTABLE);
1888c2ecf20Sopenharmony_ci		if (ret < 0)
1898c2ecf20Sopenharmony_ci			return ret;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->wpf_count; ++i) {
1938c2ecf20Sopenharmony_ci		/*
1948c2ecf20Sopenharmony_ci		 * Connect the video device to the WPF. All connections are
1958c2ecf20Sopenharmony_ci		 * immutable.
1968c2ecf20Sopenharmony_ci		 */
1978c2ecf20Sopenharmony_ci		struct vsp1_rwpf *wpf = vsp1->wpf[i];
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		ret = media_create_pad_link(&wpf->entity.subdev.entity,
2008c2ecf20Sopenharmony_ci					    RWPF_PAD_SOURCE,
2018c2ecf20Sopenharmony_ci					    &wpf->video->video.entity, 0,
2028c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_IMMUTABLE |
2038c2ecf20Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED);
2048c2ecf20Sopenharmony_ci		if (ret < 0)
2058c2ecf20Sopenharmony_ci			return ret;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return 0;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic void vsp1_destroy_entities(struct vsp1_device *vsp1)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct vsp1_entity *entity, *_entity;
2148c2ecf20Sopenharmony_ci	struct vsp1_video *video, *_video;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) {
2178c2ecf20Sopenharmony_ci		list_del(&entity->list_dev);
2188c2ecf20Sopenharmony_ci		vsp1_entity_destroy(entity);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	list_for_each_entry_safe(video, _video, &vsp1->videos, list) {
2228c2ecf20Sopenharmony_ci		list_del(&video->list);
2238c2ecf20Sopenharmony_ci		vsp1_video_cleanup(video);
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	v4l2_device_unregister(&vsp1->v4l2_dev);
2278c2ecf20Sopenharmony_ci	if (vsp1->info->uapi)
2288c2ecf20Sopenharmony_ci		media_device_unregister(&vsp1->media_dev);
2298c2ecf20Sopenharmony_ci	media_device_cleanup(&vsp1->media_dev);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (!vsp1->info->uapi)
2328c2ecf20Sopenharmony_ci		vsp1_drm_cleanup(vsp1);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int vsp1_create_entities(struct vsp1_device *vsp1)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct media_device *mdev = &vsp1->media_dev;
2388c2ecf20Sopenharmony_ci	struct v4l2_device *vdev = &vsp1->v4l2_dev;
2398c2ecf20Sopenharmony_ci	struct vsp1_entity *entity;
2408c2ecf20Sopenharmony_ci	unsigned int i;
2418c2ecf20Sopenharmony_ci	int ret;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	mdev->dev = vsp1->dev;
2448c2ecf20Sopenharmony_ci	mdev->hw_revision = vsp1->version;
2458c2ecf20Sopenharmony_ci	strscpy(mdev->model, vsp1->info->model, sizeof(mdev->model));
2468c2ecf20Sopenharmony_ci	snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
2478c2ecf20Sopenharmony_ci		 dev_name(mdev->dev));
2488c2ecf20Sopenharmony_ci	media_device_init(mdev);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	vsp1->media_ops.link_setup = vsp1_entity_link_setup;
2518c2ecf20Sopenharmony_ci	/*
2528c2ecf20Sopenharmony_ci	 * Don't perform link validation when the userspace API is disabled as
2538c2ecf20Sopenharmony_ci	 * the pipeline is configured internally by the driver in that case, and
2548c2ecf20Sopenharmony_ci	 * its configuration can thus be trusted.
2558c2ecf20Sopenharmony_ci	 */
2568c2ecf20Sopenharmony_ci	if (vsp1->info->uapi)
2578c2ecf20Sopenharmony_ci		vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	vdev->mdev = mdev;
2608c2ecf20Sopenharmony_ci	ret = v4l2_device_register(vsp1->dev, vdev);
2618c2ecf20Sopenharmony_ci	if (ret < 0) {
2628c2ecf20Sopenharmony_ci		dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
2638c2ecf20Sopenharmony_ci			ret);
2648c2ecf20Sopenharmony_ci		goto done;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Instantiate all the entities. */
2688c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_BRS)) {
2698c2ecf20Sopenharmony_ci		vsp1->brs = vsp1_brx_create(vsp1, VSP1_ENTITY_BRS);
2708c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->brs)) {
2718c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->brs);
2728c2ecf20Sopenharmony_ci			goto done;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->brs->entity.list_dev, &vsp1->entities);
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_BRU)) {
2798c2ecf20Sopenharmony_ci		vsp1->bru = vsp1_brx_create(vsp1, VSP1_ENTITY_BRU);
2808c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->bru)) {
2818c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->bru);
2828c2ecf20Sopenharmony_ci			goto done;
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_CLU)) {
2898c2ecf20Sopenharmony_ci		vsp1->clu = vsp1_clu_create(vsp1);
2908c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->clu)) {
2918c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->clu);
2928c2ecf20Sopenharmony_ci			goto done;
2938c2ecf20Sopenharmony_ci		}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities);
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	vsp1->hsi = vsp1_hsit_create(vsp1, true);
2998c2ecf20Sopenharmony_ci	if (IS_ERR(vsp1->hsi)) {
3008c2ecf20Sopenharmony_ci		ret = PTR_ERR(vsp1->hsi);
3018c2ecf20Sopenharmony_ci		goto done;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	vsp1->hst = vsp1_hsit_create(vsp1, false);
3078c2ecf20Sopenharmony_ci	if (IS_ERR(vsp1->hst)) {
3088c2ecf20Sopenharmony_ci		ret = PTR_ERR(vsp1->hst);
3098c2ecf20Sopenharmony_ci		goto done;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_HGO) && vsp1->info->uapi) {
3158c2ecf20Sopenharmony_ci		vsp1->hgo = vsp1_hgo_create(vsp1);
3168c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->hgo)) {
3178c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->hgo);
3188c2ecf20Sopenharmony_ci			goto done;
3198c2ecf20Sopenharmony_ci		}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->hgo->histo.entity.list_dev,
3228c2ecf20Sopenharmony_ci			      &vsp1->entities);
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_HGT) && vsp1->info->uapi) {
3268c2ecf20Sopenharmony_ci		vsp1->hgt = vsp1_hgt_create(vsp1);
3278c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->hgt)) {
3288c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->hgt);
3298c2ecf20Sopenharmony_ci			goto done;
3308c2ecf20Sopenharmony_ci		}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->hgt->histo.entity.list_dev,
3338c2ecf20Sopenharmony_ci			      &vsp1->entities);
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/*
3378c2ecf20Sopenharmony_ci	 * The LIFs are only supported when used in conjunction with the DU, in
3388c2ecf20Sopenharmony_ci	 * which case the userspace API is disabled. If the userspace API is
3398c2ecf20Sopenharmony_ci	 * enabled skip the LIFs, even when present.
3408c2ecf20Sopenharmony_ci	 */
3418c2ecf20Sopenharmony_ci	if (!vsp1->info->uapi) {
3428c2ecf20Sopenharmony_ci		for (i = 0; i < vsp1->info->lif_count; ++i) {
3438c2ecf20Sopenharmony_ci			struct vsp1_lif *lif;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci			lif = vsp1_lif_create(vsp1, i);
3468c2ecf20Sopenharmony_ci			if (IS_ERR(lif)) {
3478c2ecf20Sopenharmony_ci				ret = PTR_ERR(lif);
3488c2ecf20Sopenharmony_ci				goto done;
3498c2ecf20Sopenharmony_ci			}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci			vsp1->lif[i] = lif;
3528c2ecf20Sopenharmony_ci			list_add_tail(&lif->entity.list_dev, &vsp1->entities);
3538c2ecf20Sopenharmony_ci		}
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_LUT)) {
3578c2ecf20Sopenharmony_ci		vsp1->lut = vsp1_lut_create(vsp1);
3588c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->lut)) {
3598c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->lut);
3608c2ecf20Sopenharmony_ci			goto done;
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->rpf_count; ++i) {
3678c2ecf20Sopenharmony_ci		struct vsp1_rwpf *rpf;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		rpf = vsp1_rpf_create(vsp1, i);
3708c2ecf20Sopenharmony_ci		if (IS_ERR(rpf)) {
3718c2ecf20Sopenharmony_ci			ret = PTR_ERR(rpf);
3728c2ecf20Sopenharmony_ci			goto done;
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci		vsp1->rpf[i] = rpf;
3768c2ecf20Sopenharmony_ci		list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci		if (vsp1->info->uapi) {
3798c2ecf20Sopenharmony_ci			struct vsp1_video *video = vsp1_video_create(vsp1, rpf);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci			if (IS_ERR(video)) {
3828c2ecf20Sopenharmony_ci				ret = PTR_ERR(video);
3838c2ecf20Sopenharmony_ci				goto done;
3848c2ecf20Sopenharmony_ci			}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci			list_add_tail(&video->list, &vsp1->videos);
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_SRU)) {
3918c2ecf20Sopenharmony_ci		vsp1->sru = vsp1_sru_create(vsp1);
3928c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->sru)) {
3938c2ecf20Sopenharmony_ci			ret = PTR_ERR(vsp1->sru);
3948c2ecf20Sopenharmony_ci			goto done;
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->uds_count; ++i) {
4018c2ecf20Sopenharmony_ci		struct vsp1_uds *uds;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		uds = vsp1_uds_create(vsp1, i);
4048c2ecf20Sopenharmony_ci		if (IS_ERR(uds)) {
4058c2ecf20Sopenharmony_ci			ret = PTR_ERR(uds);
4068c2ecf20Sopenharmony_ci			goto done;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		vsp1->uds[i] = uds;
4108c2ecf20Sopenharmony_ci		list_add_tail(&uds->entity.list_dev, &vsp1->entities);
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->uif_count; ++i) {
4148c2ecf20Sopenharmony_ci		struct vsp1_uif *uif;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		uif = vsp1_uif_create(vsp1, i);
4178c2ecf20Sopenharmony_ci		if (IS_ERR(uif)) {
4188c2ecf20Sopenharmony_ci			ret = PTR_ERR(uif);
4198c2ecf20Sopenharmony_ci			goto done;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		vsp1->uif[i] = uif;
4238c2ecf20Sopenharmony_ci		list_add_tail(&uif->entity.list_dev, &vsp1->entities);
4248c2ecf20Sopenharmony_ci	}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->wpf_count; ++i) {
4278c2ecf20Sopenharmony_ci		struct vsp1_rwpf *wpf;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		wpf = vsp1_wpf_create(vsp1, i);
4308c2ecf20Sopenharmony_ci		if (IS_ERR(wpf)) {
4318c2ecf20Sopenharmony_ci			ret = PTR_ERR(wpf);
4328c2ecf20Sopenharmony_ci			goto done;
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		vsp1->wpf[i] = wpf;
4368c2ecf20Sopenharmony_ci		list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		if (vsp1->info->uapi) {
4398c2ecf20Sopenharmony_ci			struct vsp1_video *video = vsp1_video_create(vsp1, wpf);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci			if (IS_ERR(video)) {
4428c2ecf20Sopenharmony_ci				ret = PTR_ERR(video);
4438c2ecf20Sopenharmony_ci				goto done;
4448c2ecf20Sopenharmony_ci			}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			list_add_tail(&video->list, &vsp1->videos);
4478c2ecf20Sopenharmony_ci		}
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/* Register all subdevs. */
4518c2ecf20Sopenharmony_ci	list_for_each_entry(entity, &vsp1->entities, list_dev) {
4528c2ecf20Sopenharmony_ci		ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
4538c2ecf20Sopenharmony_ci						  &entity->subdev);
4548c2ecf20Sopenharmony_ci		if (ret < 0)
4558c2ecf20Sopenharmony_ci			goto done;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/*
4598c2ecf20Sopenharmony_ci	 * Create links and register subdev nodes if the userspace API is
4608c2ecf20Sopenharmony_ci	 * enabled or initialize the DRM pipeline otherwise.
4618c2ecf20Sopenharmony_ci	 */
4628c2ecf20Sopenharmony_ci	if (vsp1->info->uapi) {
4638c2ecf20Sopenharmony_ci		ret = vsp1_uapi_create_links(vsp1);
4648c2ecf20Sopenharmony_ci		if (ret < 0)
4658c2ecf20Sopenharmony_ci			goto done;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
4688c2ecf20Sopenharmony_ci		if (ret < 0)
4698c2ecf20Sopenharmony_ci			goto done;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		ret = media_device_register(mdev);
4728c2ecf20Sopenharmony_ci	} else {
4738c2ecf20Sopenharmony_ci		ret = vsp1_drm_init(vsp1);
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cidone:
4778c2ecf20Sopenharmony_ci	if (ret < 0)
4788c2ecf20Sopenharmony_ci		vsp1_destroy_entities(vsp1);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	return ret;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ciint vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	unsigned int timeout;
4868c2ecf20Sopenharmony_ci	u32 status;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	status = vsp1_read(vsp1, VI6_STATUS);
4898c2ecf20Sopenharmony_ci	if (!(status & VI6_STATUS_SYS_ACT(index)))
4908c2ecf20Sopenharmony_ci		return 0;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
4938c2ecf20Sopenharmony_ci	for (timeout = 10; timeout > 0; --timeout) {
4948c2ecf20Sopenharmony_ci		status = vsp1_read(vsp1, VI6_STATUS);
4958c2ecf20Sopenharmony_ci		if (!(status & VI6_STATUS_SYS_ACT(index)))
4968c2ecf20Sopenharmony_ci			break;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (!timeout) {
5028c2ecf20Sopenharmony_ci		dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
5038c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	return 0;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int vsp1_device_init(struct vsp1_device *vsp1)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	unsigned int i;
5128c2ecf20Sopenharmony_ci	int ret;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	/* Reset any channel that might be running. */
5158c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->wpf_count; ++i) {
5168c2ecf20Sopenharmony_ci		ret = vsp1_reset_wpf(vsp1, i);
5178c2ecf20Sopenharmony_ci		if (ret < 0)
5188c2ecf20Sopenharmony_ci			return ret;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
5228c2ecf20Sopenharmony_ci		   (8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->rpf_count; ++i)
5258c2ecf20Sopenharmony_ci		vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->uds_count; ++i)
5288c2ecf20Sopenharmony_ci		vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	for (i = 0; i < vsp1->info->uif_count; ++i)
5318c2ecf20Sopenharmony_ci		vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
5348c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
5358c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
5368c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
5378c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
5388c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if (vsp1_feature(vsp1, VSP1_HAS_BRS))
5418c2ecf20Sopenharmony_ci		vsp1_write(vsp1, VI6_DPR_ILV_BRS_ROUTE, VI6_DPR_NODE_UNUSED);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
5448c2ecf20Sopenharmony_ci		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
5458c2ecf20Sopenharmony_ci	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
5468c2ecf20Sopenharmony_ci		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	vsp1_dlm_setup(vsp1);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci/*
5548c2ecf20Sopenharmony_ci * vsp1_device_get - Acquire the VSP1 device
5558c2ecf20Sopenharmony_ci *
5568c2ecf20Sopenharmony_ci * Make sure the device is not suspended and initialize it if needed.
5578c2ecf20Sopenharmony_ci *
5588c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise.
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_ciint vsp1_device_get(struct vsp1_device *vsp1)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	int ret;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(vsp1->dev);
5658c2ecf20Sopenharmony_ci	if (ret < 0) {
5668c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(vsp1->dev);
5678c2ecf20Sopenharmony_ci		return ret;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	return 0;
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci/*
5748c2ecf20Sopenharmony_ci * vsp1_device_put - Release the VSP1 device
5758c2ecf20Sopenharmony_ci *
5768c2ecf20Sopenharmony_ci * Decrement the VSP1 reference count and cleanup the device if the last
5778c2ecf20Sopenharmony_ci * reference is released.
5788c2ecf20Sopenharmony_ci */
5798c2ecf20Sopenharmony_civoid vsp1_device_put(struct vsp1_device *vsp1)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	pm_runtime_put_sync(vsp1->dev);
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
5858c2ecf20Sopenharmony_ci * Power Management
5868c2ecf20Sopenharmony_ci */
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic int __maybe_unused vsp1_pm_suspend(struct device *dev)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/*
5938c2ecf20Sopenharmony_ci	 * When used as part of a display pipeline, the VSP is stopped and
5948c2ecf20Sopenharmony_ci	 * restarted explicitly by the DU.
5958c2ecf20Sopenharmony_ci	 */
5968c2ecf20Sopenharmony_ci	if (!vsp1->drm)
5978c2ecf20Sopenharmony_ci		vsp1_video_suspend(vsp1);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	pm_runtime_force_suspend(vsp1->dev);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return 0;
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int __maybe_unused vsp1_pm_resume(struct device *dev)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	pm_runtime_force_resume(vsp1->dev);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/*
6118c2ecf20Sopenharmony_ci	 * When used as part of a display pipeline, the VSP is stopped and
6128c2ecf20Sopenharmony_ci	 * restarted explicitly by the DU.
6138c2ecf20Sopenharmony_ci	 */
6148c2ecf20Sopenharmony_ci	if (!vsp1->drm)
6158c2ecf20Sopenharmony_ci		vsp1_video_resume(vsp1);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	return 0;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	rcar_fcp_disable(vsp1->fcp);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return 0;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int __maybe_unused vsp1_pm_runtime_resume(struct device *dev)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
6328c2ecf20Sopenharmony_ci	int ret;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (vsp1->info) {
6358c2ecf20Sopenharmony_ci		ret = vsp1_device_init(vsp1);
6368c2ecf20Sopenharmony_ci		if (ret < 0)
6378c2ecf20Sopenharmony_ci			return ret;
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	return rcar_fcp_enable(vsp1->fcp);
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_cistatic const struct dev_pm_ops vsp1_pm_ops = {
6448c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
6458c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL)
6468c2ecf20Sopenharmony_ci};
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------------
6498c2ecf20Sopenharmony_ci * Platform Driver
6508c2ecf20Sopenharmony_ci */
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic const struct vsp1_device_info vsp1_device_infos[] = {
6538c2ecf20Sopenharmony_ci	{
6548c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPS_H2,
6558c2ecf20Sopenharmony_ci		.model = "VSP1-S",
6568c2ecf20Sopenharmony_ci		.gen = 2,
6578c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
6588c2ecf20Sopenharmony_ci			  | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
6598c2ecf20Sopenharmony_ci			  | VSP1_HAS_WPF_VFLIP,
6608c2ecf20Sopenharmony_ci		.rpf_count = 5,
6618c2ecf20Sopenharmony_ci		.uds_count = 3,
6628c2ecf20Sopenharmony_ci		.wpf_count = 4,
6638c2ecf20Sopenharmony_ci		.num_bru_inputs = 4,
6648c2ecf20Sopenharmony_ci		.uapi = true,
6658c2ecf20Sopenharmony_ci	}, {
6668c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPR_H2,
6678c2ecf20Sopenharmony_ci		.model = "VSP1-R",
6688c2ecf20Sopenharmony_ci		.gen = 2,
6698c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
6708c2ecf20Sopenharmony_ci		.rpf_count = 5,
6718c2ecf20Sopenharmony_ci		.uds_count = 3,
6728c2ecf20Sopenharmony_ci		.wpf_count = 4,
6738c2ecf20Sopenharmony_ci		.num_bru_inputs = 4,
6748c2ecf20Sopenharmony_ci		.uapi = true,
6758c2ecf20Sopenharmony_ci	}, {
6768c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
6778c2ecf20Sopenharmony_ci		.model = "VSP1-D",
6788c2ecf20Sopenharmony_ci		.gen = 2,
6798c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LUT,
6808c2ecf20Sopenharmony_ci		.lif_count = 1,
6818c2ecf20Sopenharmony_ci		.rpf_count = 4,
6828c2ecf20Sopenharmony_ci		.uds_count = 1,
6838c2ecf20Sopenharmony_ci		.wpf_count = 1,
6848c2ecf20Sopenharmony_ci		.num_bru_inputs = 4,
6858c2ecf20Sopenharmony_ci		.uapi = true,
6868c2ecf20Sopenharmony_ci	}, {
6878c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPS_M2,
6888c2ecf20Sopenharmony_ci		.model = "VSP1-S",
6898c2ecf20Sopenharmony_ci		.gen = 2,
6908c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
6918c2ecf20Sopenharmony_ci			  | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU
6928c2ecf20Sopenharmony_ci			  | VSP1_HAS_WPF_VFLIP,
6938c2ecf20Sopenharmony_ci		.rpf_count = 5,
6948c2ecf20Sopenharmony_ci		.uds_count = 1,
6958c2ecf20Sopenharmony_ci		.wpf_count = 4,
6968c2ecf20Sopenharmony_ci		.num_bru_inputs = 4,
6978c2ecf20Sopenharmony_ci		.uapi = true,
6988c2ecf20Sopenharmony_ci	}, {
6998c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPS_V2H,
7008c2ecf20Sopenharmony_ci		.model = "VSP1V-S",
7018c2ecf20Sopenharmony_ci		.gen = 2,
7028c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT
7038c2ecf20Sopenharmony_ci			  | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP,
7048c2ecf20Sopenharmony_ci		.rpf_count = 4,
7058c2ecf20Sopenharmony_ci		.uds_count = 1,
7068c2ecf20Sopenharmony_ci		.wpf_count = 4,
7078c2ecf20Sopenharmony_ci		.num_bru_inputs = 4,
7088c2ecf20Sopenharmony_ci		.uapi = true,
7098c2ecf20Sopenharmony_ci	}, {
7108c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPD_V2H,
7118c2ecf20Sopenharmony_ci		.model = "VSP1V-D",
7128c2ecf20Sopenharmony_ci		.gen = 2,
7138c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT,
7148c2ecf20Sopenharmony_ci		.lif_count = 1,
7158c2ecf20Sopenharmony_ci		.rpf_count = 4,
7168c2ecf20Sopenharmony_ci		.uds_count = 1,
7178c2ecf20Sopenharmony_ci		.wpf_count = 1,
7188c2ecf20Sopenharmony_ci		.num_bru_inputs = 4,
7198c2ecf20Sopenharmony_ci		.uapi = true,
7208c2ecf20Sopenharmony_ci	}, {
7218c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
7228c2ecf20Sopenharmony_ci		.model = "VSP2-I",
7238c2ecf20Sopenharmony_ci		.gen = 3,
7248c2ecf20Sopenharmony_ci		.features = VSP1_HAS_CLU | VSP1_HAS_HGO | VSP1_HAS_HGT
7258c2ecf20Sopenharmony_ci			  | VSP1_HAS_LUT | VSP1_HAS_SRU | VSP1_HAS_WPF_HFLIP
7268c2ecf20Sopenharmony_ci			  | VSP1_HAS_WPF_VFLIP,
7278c2ecf20Sopenharmony_ci		.rpf_count = 1,
7288c2ecf20Sopenharmony_ci		.uds_count = 1,
7298c2ecf20Sopenharmony_ci		.wpf_count = 1,
7308c2ecf20Sopenharmony_ci		.uapi = true,
7318c2ecf20Sopenharmony_ci	}, {
7328c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
7338c2ecf20Sopenharmony_ci		.model = "VSP2-BD",
7348c2ecf20Sopenharmony_ci		.gen = 3,
7358c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP,
7368c2ecf20Sopenharmony_ci		.rpf_count = 5,
7378c2ecf20Sopenharmony_ci		.wpf_count = 1,
7388c2ecf20Sopenharmony_ci		.num_bru_inputs = 5,
7398c2ecf20Sopenharmony_ci		.uapi = true,
7408c2ecf20Sopenharmony_ci	}, {
7418c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
7428c2ecf20Sopenharmony_ci		.model = "VSP2-BC",
7438c2ecf20Sopenharmony_ci		.gen = 3,
7448c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO
7458c2ecf20Sopenharmony_ci			  | VSP1_HAS_LUT | VSP1_HAS_WPF_VFLIP,
7468c2ecf20Sopenharmony_ci		.rpf_count = 5,
7478c2ecf20Sopenharmony_ci		.wpf_count = 1,
7488c2ecf20Sopenharmony_ci		.num_bru_inputs = 5,
7498c2ecf20Sopenharmony_ci		.uapi = true,
7508c2ecf20Sopenharmony_ci	}, {
7518c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPBS_GEN3,
7528c2ecf20Sopenharmony_ci		.model = "VSP2-BS",
7538c2ecf20Sopenharmony_ci		.gen = 3,
7548c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP,
7558c2ecf20Sopenharmony_ci		.rpf_count = 2,
7568c2ecf20Sopenharmony_ci		.wpf_count = 1,
7578c2ecf20Sopenharmony_ci		.uapi = true,
7588c2ecf20Sopenharmony_ci	}, {
7598c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
7608c2ecf20Sopenharmony_ci		.model = "VSP2-D",
7618c2ecf20Sopenharmony_ci		.gen = 3,
7628c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP | VSP1_HAS_EXT_DL,
7638c2ecf20Sopenharmony_ci		.lif_count = 1,
7648c2ecf20Sopenharmony_ci		.rpf_count = 5,
7658c2ecf20Sopenharmony_ci		.uif_count = 1,
7668c2ecf20Sopenharmony_ci		.wpf_count = 2,
7678c2ecf20Sopenharmony_ci		.num_bru_inputs = 5,
7688c2ecf20Sopenharmony_ci	}, {
7698c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPD_V3,
7708c2ecf20Sopenharmony_ci		.model = "VSP2-D",
7718c2ecf20Sopenharmony_ci		.gen = 3,
7728c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRS | VSP1_HAS_BRU,
7738c2ecf20Sopenharmony_ci		.lif_count = 1,
7748c2ecf20Sopenharmony_ci		.rpf_count = 5,
7758c2ecf20Sopenharmony_ci		.uif_count = 1,
7768c2ecf20Sopenharmony_ci		.wpf_count = 1,
7778c2ecf20Sopenharmony_ci		.num_bru_inputs = 5,
7788c2ecf20Sopenharmony_ci	}, {
7798c2ecf20Sopenharmony_ci		.version = VI6_IP_VERSION_MODEL_VSPDL_GEN3,
7808c2ecf20Sopenharmony_ci		.model = "VSP2-DL",
7818c2ecf20Sopenharmony_ci		.gen = 3,
7828c2ecf20Sopenharmony_ci		.features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_EXT_DL,
7838c2ecf20Sopenharmony_ci		.lif_count = 2,
7848c2ecf20Sopenharmony_ci		.rpf_count = 5,
7858c2ecf20Sopenharmony_ci		.uif_count = 2,
7868c2ecf20Sopenharmony_ci		.wpf_count = 2,
7878c2ecf20Sopenharmony_ci		.num_bru_inputs = 5,
7888c2ecf20Sopenharmony_ci	},
7898c2ecf20Sopenharmony_ci};
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_cistatic int vsp1_probe(struct platform_device *pdev)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1;
7948c2ecf20Sopenharmony_ci	struct device_node *fcp_node;
7958c2ecf20Sopenharmony_ci	struct resource *irq;
7968c2ecf20Sopenharmony_ci	struct resource *io;
7978c2ecf20Sopenharmony_ci	unsigned int i;
7988c2ecf20Sopenharmony_ci	int ret;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
8018c2ecf20Sopenharmony_ci	if (vsp1 == NULL)
8028c2ecf20Sopenharmony_ci		return -ENOMEM;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	vsp1->dev = &pdev->dev;
8058c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vsp1->entities);
8068c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vsp1->videos);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, vsp1);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	/* I/O and IRQ resources (clock managed by the clock PM domain). */
8118c2ecf20Sopenharmony_ci	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8128c2ecf20Sopenharmony_ci	vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
8138c2ecf20Sopenharmony_ci	if (IS_ERR(vsp1->mmio))
8148c2ecf20Sopenharmony_ci		return PTR_ERR(vsp1->mmio);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
8178c2ecf20Sopenharmony_ci	if (!irq) {
8188c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing IRQ\n");
8198c2ecf20Sopenharmony_ci		return -EINVAL;
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
8238c2ecf20Sopenharmony_ci			      IRQF_SHARED, dev_name(&pdev->dev), vsp1);
8248c2ecf20Sopenharmony_ci	if (ret < 0) {
8258c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to request IRQ\n");
8268c2ecf20Sopenharmony_ci		return ret;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* FCP (optional). */
8308c2ecf20Sopenharmony_ci	fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
8318c2ecf20Sopenharmony_ci	if (fcp_node) {
8328c2ecf20Sopenharmony_ci		vsp1->fcp = rcar_fcp_get(fcp_node);
8338c2ecf20Sopenharmony_ci		of_node_put(fcp_node);
8348c2ecf20Sopenharmony_ci		if (IS_ERR(vsp1->fcp)) {
8358c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev, "FCP not found (%ld)\n",
8368c2ecf20Sopenharmony_ci				PTR_ERR(vsp1->fcp));
8378c2ecf20Sopenharmony_ci			return PTR_ERR(vsp1->fcp);
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		/*
8418c2ecf20Sopenharmony_ci		 * When the FCP is present, it handles all bus master accesses
8428c2ecf20Sopenharmony_ci		 * for the VSP and must thus be used in place of the VSP device
8438c2ecf20Sopenharmony_ci		 * to map DMA buffers.
8448c2ecf20Sopenharmony_ci		 */
8458c2ecf20Sopenharmony_ci		vsp1->bus_master = rcar_fcp_get_device(vsp1->fcp);
8468c2ecf20Sopenharmony_ci	} else {
8478c2ecf20Sopenharmony_ci		vsp1->bus_master = vsp1->dev;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	/* Configure device parameters based on the version register. */
8518c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	ret = vsp1_device_get(vsp1);
8548c2ecf20Sopenharmony_ci	if (ret < 0)
8558c2ecf20Sopenharmony_ci		goto done;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
8588c2ecf20Sopenharmony_ci	vsp1_device_put(vsp1);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
8618c2ecf20Sopenharmony_ci		if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
8628c2ecf20Sopenharmony_ci		    vsp1_device_infos[i].version) {
8638c2ecf20Sopenharmony_ci			vsp1->info = &vsp1_device_infos[i];
8648c2ecf20Sopenharmony_ci			break;
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (!vsp1->info) {
8698c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "unsupported IP version 0x%08x\n",
8708c2ecf20Sopenharmony_ci			vsp1->version);
8718c2ecf20Sopenharmony_ci		ret = -ENXIO;
8728c2ecf20Sopenharmony_ci		goto done;
8738c2ecf20Sopenharmony_ci	}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* Instantiate entities. */
8788c2ecf20Sopenharmony_ci	ret = vsp1_create_entities(vsp1);
8798c2ecf20Sopenharmony_ci	if (ret < 0) {
8808c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to create entities\n");
8818c2ecf20Sopenharmony_ci		goto done;
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cidone:
8858c2ecf20Sopenharmony_ci	if (ret) {
8868c2ecf20Sopenharmony_ci		pm_runtime_disable(&pdev->dev);
8878c2ecf20Sopenharmony_ci		rcar_fcp_put(vsp1->fcp);
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	return ret;
8918c2ecf20Sopenharmony_ci}
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_cistatic int vsp1_remove(struct platform_device *pdev)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	vsp1_destroy_entities(vsp1);
8988c2ecf20Sopenharmony_ci	rcar_fcp_put(vsp1->fcp);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	return 0;
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cistatic const struct of_device_id vsp1_of_match[] = {
9068c2ecf20Sopenharmony_ci	{ .compatible = "renesas,vsp1" },
9078c2ecf20Sopenharmony_ci	{ .compatible = "renesas,vsp2" },
9088c2ecf20Sopenharmony_ci	{ },
9098c2ecf20Sopenharmony_ci};
9108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, vsp1_of_match);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic struct platform_driver vsp1_platform_driver = {
9138c2ecf20Sopenharmony_ci	.probe		= vsp1_probe,
9148c2ecf20Sopenharmony_ci	.remove		= vsp1_remove,
9158c2ecf20Sopenharmony_ci	.driver		= {
9168c2ecf20Sopenharmony_ci		.name	= "vsp1",
9178c2ecf20Sopenharmony_ci		.pm	= &vsp1_pm_ops,
9188c2ecf20Sopenharmony_ci		.of_match_table = vsp1_of_match,
9198c2ecf20Sopenharmony_ci	},
9208c2ecf20Sopenharmony_ci};
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cimodule_platform_driver(vsp1_platform_driver);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ciMODULE_ALIAS("vsp1");
9258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
9268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Renesas VSP1 Driver");
9278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
928