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