1/*
2 * vsp1_drv.c  --  R-Car VSP1 Driver
3 *
4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/interrupt.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/platform_device.h>
21#include <linux/videodev2.h>
22
23#include "vsp1.h"
24#include "vsp1_bru.h"
25#include "vsp1_hsit.h"
26#include "vsp1_lif.h"
27#include "vsp1_lut.h"
28#include "vsp1_rwpf.h"
29#include "vsp1_sru.h"
30#include "vsp1_uds.h"
31
32/* -----------------------------------------------------------------------------
33 * Interrupt Handling
34 */
35
36static irqreturn_t vsp1_irq_handler(int irq, void *data)
37{
38	u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
39	struct vsp1_device *vsp1 = data;
40	irqreturn_t ret = IRQ_NONE;
41	unsigned int i;
42
43	for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
44		struct vsp1_rwpf *wpf = vsp1->wpf[i];
45		struct vsp1_pipeline *pipe;
46		u32 status;
47
48		if (wpf == NULL)
49			continue;
50
51		pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity);
52		status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
53		vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
54
55		if (status & VI6_WFP_IRQ_STA_FRE) {
56			vsp1_pipeline_frame_end(pipe);
57			ret = IRQ_HANDLED;
58		}
59	}
60
61	return ret;
62}
63
64/* -----------------------------------------------------------------------------
65 * Entities
66 */
67
68/*
69 * vsp1_create_links - Create links from all sources to the given sink
70 *
71 * This function creates media links from all valid sources to the given sink
72 * pad. Links that would be invalid according to the VSP1 hardware capabilities
73 * are skipped. Those include all links
74 *
75 * - from a UDS to a UDS (UDS entities can't be chained)
76 * - from an entity to itself (no loops are allowed)
77 */
78static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink)
79{
80	struct media_entity *entity = &sink->subdev.entity;
81	struct vsp1_entity *source;
82	unsigned int pad;
83	int ret;
84
85	list_for_each_entry(source, &vsp1->entities, list_dev) {
86		u32 flags;
87
88		if (source->type == sink->type)
89			continue;
90
91		if (source->type == VSP1_ENTITY_LIF ||
92		    source->type == VSP1_ENTITY_WPF)
93			continue;
94
95		flags = source->type == VSP1_ENTITY_RPF &&
96			sink->type == VSP1_ENTITY_WPF &&
97			source->index == sink->index
98		      ? MEDIA_LNK_FL_ENABLED : 0;
99
100		for (pad = 0; pad < entity->num_pads; ++pad) {
101			if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
102				continue;
103
104			ret = media_entity_create_link(&source->subdev.entity,
105						       source->source_pad,
106						       entity, pad, flags);
107			if (ret < 0)
108				return ret;
109
110			if (flags & MEDIA_LNK_FL_ENABLED)
111				source->sink = entity;
112		}
113	}
114
115	return 0;
116}
117
118static void vsp1_destroy_entities(struct vsp1_device *vsp1)
119{
120	struct vsp1_entity *entity;
121	struct vsp1_entity *next;
122
123	list_for_each_entry_safe(entity, next, &vsp1->entities, list_dev) {
124		list_del(&entity->list_dev);
125		vsp1_entity_destroy(entity);
126	}
127
128	v4l2_device_unregister(&vsp1->v4l2_dev);
129	media_device_unregister(&vsp1->media_dev);
130}
131
132static int vsp1_create_entities(struct vsp1_device *vsp1)
133{
134	struct media_device *mdev = &vsp1->media_dev;
135	struct v4l2_device *vdev = &vsp1->v4l2_dev;
136	struct vsp1_entity *entity;
137	unsigned int i;
138	int ret;
139
140	mdev->dev = vsp1->dev;
141	strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
142	snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
143		 dev_name(mdev->dev));
144	ret = media_device_register(mdev);
145	if (ret < 0) {
146		dev_err(vsp1->dev, "media device registration failed (%d)\n",
147			ret);
148		return ret;
149	}
150
151	vdev->mdev = mdev;
152	ret = v4l2_device_register(vsp1->dev, vdev);
153	if (ret < 0) {
154		dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
155			ret);
156		goto done;
157	}
158
159	/* Instantiate all the entities. */
160	vsp1->bru = vsp1_bru_create(vsp1);
161	if (IS_ERR(vsp1->bru)) {
162		ret = PTR_ERR(vsp1->bru);
163		goto done;
164	}
165
166	list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
167
168	vsp1->hsi = vsp1_hsit_create(vsp1, true);
169	if (IS_ERR(vsp1->hsi)) {
170		ret = PTR_ERR(vsp1->hsi);
171		goto done;
172	}
173
174	list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
175
176	vsp1->hst = vsp1_hsit_create(vsp1, false);
177	if (IS_ERR(vsp1->hst)) {
178		ret = PTR_ERR(vsp1->hst);
179		goto done;
180	}
181
182	list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
183
184	if (vsp1->pdata.features & VSP1_HAS_LIF) {
185		vsp1->lif = vsp1_lif_create(vsp1);
186		if (IS_ERR(vsp1->lif)) {
187			ret = PTR_ERR(vsp1->lif);
188			goto done;
189		}
190
191		list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
192	}
193
194	if (vsp1->pdata.features & VSP1_HAS_LUT) {
195		vsp1->lut = vsp1_lut_create(vsp1);
196		if (IS_ERR(vsp1->lut)) {
197			ret = PTR_ERR(vsp1->lut);
198			goto done;
199		}
200
201		list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
202	}
203
204	for (i = 0; i < vsp1->pdata.rpf_count; ++i) {
205		struct vsp1_rwpf *rpf;
206
207		rpf = vsp1_rpf_create(vsp1, i);
208		if (IS_ERR(rpf)) {
209			ret = PTR_ERR(rpf);
210			goto done;
211		}
212
213		vsp1->rpf[i] = rpf;
214		list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
215	}
216
217	if (vsp1->pdata.features & VSP1_HAS_SRU) {
218		vsp1->sru = vsp1_sru_create(vsp1);
219		if (IS_ERR(vsp1->sru)) {
220			ret = PTR_ERR(vsp1->sru);
221			goto done;
222		}
223
224		list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
225	}
226
227	for (i = 0; i < vsp1->pdata.uds_count; ++i) {
228		struct vsp1_uds *uds;
229
230		uds = vsp1_uds_create(vsp1, i);
231		if (IS_ERR(uds)) {
232			ret = PTR_ERR(uds);
233			goto done;
234		}
235
236		vsp1->uds[i] = uds;
237		list_add_tail(&uds->entity.list_dev, &vsp1->entities);
238	}
239
240	for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
241		struct vsp1_rwpf *wpf;
242
243		wpf = vsp1_wpf_create(vsp1, i);
244		if (IS_ERR(wpf)) {
245			ret = PTR_ERR(wpf);
246			goto done;
247		}
248
249		vsp1->wpf[i] = wpf;
250		list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
251	}
252
253	/* Create links. */
254	list_for_each_entry(entity, &vsp1->entities, list_dev) {
255		if (entity->type == VSP1_ENTITY_LIF ||
256		    entity->type == VSP1_ENTITY_RPF)
257			continue;
258
259		ret = vsp1_create_links(vsp1, entity);
260		if (ret < 0)
261			goto done;
262	}
263
264	if (vsp1->pdata.features & VSP1_HAS_LIF) {
265		ret = media_entity_create_link(
266			&vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE,
267			&vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0);
268		if (ret < 0)
269			return ret;
270	}
271
272	/* Register all subdevs. */
273	list_for_each_entry(entity, &vsp1->entities, list_dev) {
274		ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
275						  &entity->subdev);
276		if (ret < 0)
277			goto done;
278	}
279
280	ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
281
282done:
283	if (ret < 0)
284		vsp1_destroy_entities(vsp1);
285
286	return ret;
287}
288
289static int vsp1_device_init(struct vsp1_device *vsp1)
290{
291	unsigned int i;
292	u32 status;
293
294	/* Reset any channel that might be running. */
295	status = vsp1_read(vsp1, VI6_STATUS);
296
297	for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
298		unsigned int timeout;
299
300		if (!(status & VI6_STATUS_SYS_ACT(i)))
301			continue;
302
303		vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(i));
304		for (timeout = 10; timeout > 0; --timeout) {
305			status = vsp1_read(vsp1, VI6_STATUS);
306			if (!(status & VI6_STATUS_SYS_ACT(i)))
307				break;
308
309			usleep_range(1000, 2000);
310		}
311
312		if (!timeout) {
313			dev_err(vsp1->dev, "failed to reset wpf.%u\n", i);
314			return -ETIMEDOUT;
315		}
316	}
317
318	vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
319		   (8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
320
321	for (i = 0; i < vsp1->pdata.rpf_count; ++i)
322		vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
323
324	for (i = 0; i < vsp1->pdata.uds_count; ++i)
325		vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
326
327	vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
328	vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
329	vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
330	vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
331	vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
332	vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
333
334	vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
335		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
336	vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
337		   (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
338
339	return 0;
340}
341
342/*
343 * vsp1_device_get - Acquire the VSP1 device
344 *
345 * Increment the VSP1 reference count and initialize the device if the first
346 * reference is taken.
347 *
348 * Return 0 on success or a negative error code otherwise.
349 */
350int vsp1_device_get(struct vsp1_device *vsp1)
351{
352	int ret = 0;
353
354	mutex_lock(&vsp1->lock);
355	if (vsp1->ref_count > 0)
356		goto done;
357
358	ret = clk_prepare_enable(vsp1->clock);
359	if (ret < 0)
360		goto done;
361
362	ret = vsp1_device_init(vsp1);
363	if (ret < 0) {
364		clk_disable_unprepare(vsp1->clock);
365		goto done;
366	}
367
368done:
369	if (!ret)
370		vsp1->ref_count++;
371
372	mutex_unlock(&vsp1->lock);
373	return ret;
374}
375
376/*
377 * vsp1_device_put - Release the VSP1 device
378 *
379 * Decrement the VSP1 reference count and cleanup the device if the last
380 * reference is released.
381 */
382void vsp1_device_put(struct vsp1_device *vsp1)
383{
384	mutex_lock(&vsp1->lock);
385
386	if (--vsp1->ref_count == 0)
387		clk_disable_unprepare(vsp1->clock);
388
389	mutex_unlock(&vsp1->lock);
390}
391
392/* -----------------------------------------------------------------------------
393 * Power Management
394 */
395
396#ifdef CONFIG_PM_SLEEP
397static int vsp1_pm_suspend(struct device *dev)
398{
399	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
400
401	WARN_ON(mutex_is_locked(&vsp1->lock));
402
403	if (vsp1->ref_count == 0)
404		return 0;
405
406	clk_disable_unprepare(vsp1->clock);
407	return 0;
408}
409
410static int vsp1_pm_resume(struct device *dev)
411{
412	struct vsp1_device *vsp1 = dev_get_drvdata(dev);
413
414	WARN_ON(mutex_is_locked(&vsp1->lock));
415
416	if (vsp1->ref_count)
417		return 0;
418
419	return clk_prepare_enable(vsp1->clock);
420}
421#endif
422
423static const struct dev_pm_ops vsp1_pm_ops = {
424	SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
425};
426
427/* -----------------------------------------------------------------------------
428 * Platform Driver
429 */
430
431static int vsp1_parse_dt(struct vsp1_device *vsp1)
432{
433	struct device_node *np = vsp1->dev->of_node;
434	struct vsp1_platform_data *pdata = &vsp1->pdata;
435
436	if (of_property_read_bool(np, "renesas,has-lif"))
437		pdata->features |= VSP1_HAS_LIF;
438	if (of_property_read_bool(np, "renesas,has-lut"))
439		pdata->features |= VSP1_HAS_LUT;
440	if (of_property_read_bool(np, "renesas,has-sru"))
441		pdata->features |= VSP1_HAS_SRU;
442
443	of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count);
444	of_property_read_u32(np, "renesas,#uds", &pdata->uds_count);
445	of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count);
446
447	if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) {
448		dev_err(vsp1->dev, "invalid number of RPF (%u)\n",
449			pdata->rpf_count);
450		return -EINVAL;
451	}
452
453	if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) {
454		dev_err(vsp1->dev, "invalid number of UDS (%u)\n",
455			pdata->uds_count);
456		return -EINVAL;
457	}
458
459	if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) {
460		dev_err(vsp1->dev, "invalid number of WPF (%u)\n",
461			pdata->wpf_count);
462		return -EINVAL;
463	}
464
465	return 0;
466}
467
468static int vsp1_probe(struct platform_device *pdev)
469{
470	struct vsp1_device *vsp1;
471	struct resource *irq;
472	struct resource *io;
473	int ret;
474
475	vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
476	if (vsp1 == NULL)
477		return -ENOMEM;
478
479	vsp1->dev = &pdev->dev;
480	mutex_init(&vsp1->lock);
481	INIT_LIST_HEAD(&vsp1->entities);
482
483	ret = vsp1_parse_dt(vsp1);
484	if (ret < 0)
485		return ret;
486
487	/* I/O, IRQ and clock resources */
488	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
489	vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
490	if (IS_ERR(vsp1->mmio))
491		return PTR_ERR(vsp1->mmio);
492
493	vsp1->clock = devm_clk_get(&pdev->dev, NULL);
494	if (IS_ERR(vsp1->clock)) {
495		dev_err(&pdev->dev, "failed to get clock\n");
496		return PTR_ERR(vsp1->clock);
497	}
498
499	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
500	if (!irq) {
501		dev_err(&pdev->dev, "missing IRQ\n");
502		return -EINVAL;
503	}
504
505	ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
506			      IRQF_SHARED, dev_name(&pdev->dev), vsp1);
507	if (ret < 0) {
508		dev_err(&pdev->dev, "failed to request IRQ\n");
509		return ret;
510	}
511
512	/* Instanciate entities */
513	ret = vsp1_create_entities(vsp1);
514	if (ret < 0) {
515		dev_err(&pdev->dev, "failed to create entities\n");
516		return ret;
517	}
518
519	platform_set_drvdata(pdev, vsp1);
520
521	return 0;
522}
523
524static int vsp1_remove(struct platform_device *pdev)
525{
526	struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
527
528	vsp1_destroy_entities(vsp1);
529
530	return 0;
531}
532
533static const struct of_device_id vsp1_of_match[] = {
534	{ .compatible = "renesas,vsp1" },
535	{ },
536};
537
538static struct platform_driver vsp1_platform_driver = {
539	.probe		= vsp1_probe,
540	.remove		= vsp1_remove,
541	.driver		= {
542		.name	= "vsp1",
543		.pm	= &vsp1_pm_ops,
544		.of_match_table = vsp1_of_match,
545	},
546};
547
548module_platform_driver(vsp1_platform_driver);
549
550MODULE_ALIAS("vsp1");
551MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
552MODULE_DESCRIPTION("Renesas VSP1 Driver");
553MODULE_LICENSE("GPL");
554