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