[media] v4l: vsp1: Store pipeline pointer in rwpf
[deliverable/linux.git] / drivers / media / platform / vsp1 / vsp1_drv.c
CommitLineData
26e0ca22
LP
1/*
2 * vsp1_drv.c -- R-Car VSP1 Driver
3 *
139c9286 4 * Copyright (C) 2013-2015 Renesas Electronics Corporation
26e0ca22
LP
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>
0b82fb95 19#include <linux/of.h>
a96c5fa4 20#include <linux/of_device.h>
26e0ca22
LP
21#include <linux/platform_device.h>
22#include <linux/videodev2.h>
23
babca007
LP
24#include <media/v4l2-subdev.h>
25
26e0ca22 26#include "vsp1.h"
629bb6d4 27#include "vsp1_bru.h"
1517b039 28#include "vsp1_dl.h"
f3af9572 29#include "vsp1_drm.h"
5cdf5741 30#include "vsp1_hsit.h"
26e0ca22 31#include "vsp1_lif.h"
989af883 32#include "vsp1_lut.h"
26e0ca22 33#include "vsp1_rwpf.h"
a626e64e 34#include "vsp1_sru.h"
26e0ca22 35#include "vsp1_uds.h"
9d40637a 36#include "vsp1_video.h"
26e0ca22
LP
37
38/* -----------------------------------------------------------------------------
39 * Interrupt Handling
40 */
41
42static irqreturn_t vsp1_irq_handler(int irq, void *data)
43{
44 u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE;
45 struct vsp1_device *vsp1 = data;
46 irqreturn_t ret = IRQ_NONE;
47 unsigned int i;
1517b039 48 u32 status;
26e0ca22 49
5aa2eb3c 50 for (i = 0; i < vsp1->info->wpf_count; ++i) {
26e0ca22 51 struct vsp1_rwpf *wpf = vsp1->wpf[i];
26e0ca22
LP
52
53 if (wpf == NULL)
54 continue;
55
26e0ca22
LP
56 status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i));
57 vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask);
58
59 if (status & VI6_WFP_IRQ_STA_FRE) {
ff7e97c9 60 vsp1_pipeline_frame_end(wpf->pipe);
26e0ca22
LP
61 ret = IRQ_HANDLED;
62 }
63 }
64
1517b039
TS
65 status = vsp1_read(vsp1, VI6_DISP_IRQ_STA);
66 vsp1_write(vsp1, VI6_DISP_IRQ_STA, ~status & VI6_DISP_IRQ_STA_DST);
67
68 if (status & VI6_DISP_IRQ_STA_DST) {
c2dd2513 69 vsp1_drm_display_start(vsp1);
1517b039
TS
70 ret = IRQ_HANDLED;
71 }
72
26e0ca22
LP
73 return ret;
74}
75
76/* -----------------------------------------------------------------------------
77 * Entities
78 */
79
80/*
a07dcc53 81 * vsp1_create_sink_links - Create links from all sources to the given sink
26e0ca22
LP
82 *
83 * This function creates media links from all valid sources to the given sink
84 * pad. Links that would be invalid according to the VSP1 hardware capabilities
85 * are skipped. Those include all links
86 *
87 * - from a UDS to a UDS (UDS entities can't be chained)
88 * - from an entity to itself (no loops are allowed)
89 */
a07dcc53
LP
90static int vsp1_create_sink_links(struct vsp1_device *vsp1,
91 struct vsp1_entity *sink)
26e0ca22
LP
92{
93 struct media_entity *entity = &sink->subdev.entity;
94 struct vsp1_entity *source;
95 unsigned int pad;
96 int ret;
97
98 list_for_each_entry(source, &vsp1->entities, list_dev) {
99 u32 flags;
100
101 if (source->type == sink->type)
102 continue;
103
104 if (source->type == VSP1_ENTITY_LIF ||
105 source->type == VSP1_ENTITY_WPF)
106 continue;
107
108 flags = source->type == VSP1_ENTITY_RPF &&
109 sink->type == VSP1_ENTITY_WPF &&
110 source->index == sink->index
111 ? MEDIA_LNK_FL_ENABLED : 0;
112
113 for (pad = 0; pad < entity->num_pads; ++pad) {
114 if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK))
115 continue;
116
8df00a15 117 ret = media_create_pad_link(&source->subdev.entity,
26e0ca22
LP
118 source->source_pad,
119 entity, pad, flags);
120 if (ret < 0)
121 return ret;
db32eb6c
KM
122
123 if (flags & MEDIA_LNK_FL_ENABLED)
124 source->sink = entity;
26e0ca22
LP
125 }
126 }
127
a07dcc53
LP
128 return 0;
129}
1ad3dfed 130
f3af9572 131static int vsp1_uapi_create_links(struct vsp1_device *vsp1)
a07dcc53
LP
132{
133 struct vsp1_entity *entity;
134 unsigned int i;
135 int ret;
136
137 list_for_each_entry(entity, &vsp1->entities, list_dev) {
138 if (entity->type == VSP1_ENTITY_LIF ||
139 entity->type == VSP1_ENTITY_RPF)
140 continue;
141
142 ret = vsp1_create_sink_links(vsp1, entity);
143 if (ret < 0)
144 return ret;
145 }
146
5aa2eb3c 147 if (vsp1->info->features & VSP1_HAS_LIF) {
a07dcc53
LP
148 ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
149 RWPF_PAD_SOURCE,
150 &vsp1->lif->entity.subdev.entity,
151 LIF_PAD_SINK, 0);
152 if (ret < 0)
153 return ret;
154 }
155
5aa2eb3c 156 for (i = 0; i < vsp1->info->rpf_count; ++i) {
a07dcc53
LP
157 struct vsp1_rwpf *rpf = vsp1->rpf[i];
158
159 ret = media_create_pad_link(&rpf->video->video.entity, 0,
160 &rpf->entity.subdev.entity,
161 RWPF_PAD_SINK,
162 MEDIA_LNK_FL_ENABLED |
163 MEDIA_LNK_FL_IMMUTABLE);
164 if (ret < 0)
165 return ret;
166 }
167
5aa2eb3c 168 for (i = 0; i < vsp1->info->wpf_count; ++i) {
1ad3dfed
LP
169 /* Connect the video device to the WPF. All connections are
170 * immutable except for the WPF0 source link if a LIF is
171 * present.
172 */
a07dcc53
LP
173 struct vsp1_rwpf *wpf = vsp1->wpf[i];
174 unsigned int flags = MEDIA_LNK_FL_ENABLED;
175
5aa2eb3c 176 if (!(vsp1->info->features & VSP1_HAS_LIF) || i != 0)
1ad3dfed
LP
177 flags |= MEDIA_LNK_FL_IMMUTABLE;
178
a07dcc53
LP
179 ret = media_create_pad_link(&wpf->entity.subdev.entity,
180 RWPF_PAD_SOURCE,
181 &wpf->video->video.entity, 0,
182 flags);
183 if (ret < 0)
184 return ret;
1ad3dfed
LP
185 }
186
26e0ca22
LP
187 return 0;
188}
189
190static void vsp1_destroy_entities(struct vsp1_device *vsp1)
191{
9d40637a
LP
192 struct vsp1_entity *entity, *_entity;
193 struct vsp1_video *video, *_video;
26e0ca22 194
9d40637a 195 list_for_each_entry_safe(entity, _entity, &vsp1->entities, list_dev) {
26e0ca22
LP
196 list_del(&entity->list_dev);
197 vsp1_entity_destroy(entity);
198 }
199
9d40637a
LP
200 list_for_each_entry_safe(video, _video, &vsp1->videos, list) {
201 list_del(&video->list);
202 vsp1_video_cleanup(video);
203 }
204
26e0ca22
LP
205 v4l2_device_unregister(&vsp1->v4l2_dev);
206 media_device_unregister(&vsp1->media_dev);
9832e155 207 media_device_cleanup(&vsp1->media_dev);
1517b039 208
5aa2eb3c 209 if (!vsp1->info->uapi)
1517b039 210 vsp1_drm_cleanup(vsp1);
26e0ca22
LP
211}
212
213static int vsp1_create_entities(struct vsp1_device *vsp1)
214{
215 struct media_device *mdev = &vsp1->media_dev;
216 struct v4l2_device *vdev = &vsp1->v4l2_dev;
217 struct vsp1_entity *entity;
218 unsigned int i;
219 int ret;
220
221 mdev->dev = vsp1->dev;
222 strlcpy(mdev->model, "VSP1", sizeof(mdev->model));
10d79b99
LP
223 snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
224 dev_name(mdev->dev));
9832e155 225 media_device_init(mdev);
26e0ca22 226
babca007
LP
227 vsp1->media_ops.link_setup = vsp1_entity_link_setup;
228 /* Don't perform link validation when the userspace API is disabled as
229 * the pipeline is configured internally by the driver in that case, and
230 * its configuration can thus be trusted.
231 */
5aa2eb3c 232 if (vsp1->info->uapi)
babca007
LP
233 vsp1->media_ops.link_validate = v4l2_subdev_link_validate;
234
26e0ca22
LP
235 vdev->mdev = mdev;
236 ret = v4l2_device_register(vsp1->dev, vdev);
237 if (ret < 0) {
238 dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n",
239 ret);
240 goto done;
241 }
242
243 /* Instantiate all the entities. */
5aa2eb3c 244 if (vsp1->info->features & VSP1_HAS_BRU) {
f74be412
LP
245 vsp1->bru = vsp1_bru_create(vsp1);
246 if (IS_ERR(vsp1->bru)) {
247 ret = PTR_ERR(vsp1->bru);
248 goto done;
249 }
629bb6d4 250
f74be412
LP
251 list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities);
252 }
629bb6d4 253
5cdf5741
LP
254 vsp1->hsi = vsp1_hsit_create(vsp1, true);
255 if (IS_ERR(vsp1->hsi)) {
256 ret = PTR_ERR(vsp1->hsi);
257 goto done;
258 }
259
260 list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
261
262 vsp1->hst = vsp1_hsit_create(vsp1, false);
263 if (IS_ERR(vsp1->hst)) {
264 ret = PTR_ERR(vsp1->hst);
265 goto done;
266 }
267
268 list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
269
5aa2eb3c 270 if (vsp1->info->features & VSP1_HAS_LIF) {
26e0ca22
LP
271 vsp1->lif = vsp1_lif_create(vsp1);
272 if (IS_ERR(vsp1->lif)) {
273 ret = PTR_ERR(vsp1->lif);
274 goto done;
275 }
276
277 list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
278 }
279
5aa2eb3c 280 if (vsp1->info->features & VSP1_HAS_LUT) {
989af883
LP
281 vsp1->lut = vsp1_lut_create(vsp1);
282 if (IS_ERR(vsp1->lut)) {
283 ret = PTR_ERR(vsp1->lut);
284 goto done;
285 }
286
287 list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
288 }
289
5aa2eb3c 290 for (i = 0; i < vsp1->info->rpf_count; ++i) {
26e0ca22
LP
291 struct vsp1_rwpf *rpf;
292
293 rpf = vsp1_rpf_create(vsp1, i);
294 if (IS_ERR(rpf)) {
295 ret = PTR_ERR(rpf);
296 goto done;
297 }
298
299 vsp1->rpf[i] = rpf;
300 list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
9d40637a 301
5aa2eb3c 302 if (vsp1->info->uapi) {
f2ed459d 303 struct vsp1_video *video = vsp1_video_create(vsp1, rpf);
9d40637a 304
f2ed459d
LP
305 if (IS_ERR(video)) {
306 ret = PTR_ERR(video);
307 goto done;
308 }
309
310 list_add_tail(&video->list, &vsp1->videos);
311 }
26e0ca22
LP
312 }
313
5aa2eb3c 314 if (vsp1->info->features & VSP1_HAS_SRU) {
a626e64e
LP
315 vsp1->sru = vsp1_sru_create(vsp1);
316 if (IS_ERR(vsp1->sru)) {
317 ret = PTR_ERR(vsp1->sru);
318 goto done;
319 }
320
321 list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
322 }
323
5aa2eb3c 324 for (i = 0; i < vsp1->info->uds_count; ++i) {
26e0ca22
LP
325 struct vsp1_uds *uds;
326
327 uds = vsp1_uds_create(vsp1, i);
328 if (IS_ERR(uds)) {
329 ret = PTR_ERR(uds);
330 goto done;
331 }
332
333 vsp1->uds[i] = uds;
334 list_add_tail(&uds->entity.list_dev, &vsp1->entities);
335 }
336
5aa2eb3c 337 for (i = 0; i < vsp1->info->wpf_count; ++i) {
26e0ca22
LP
338 struct vsp1_rwpf *wpf;
339
340 wpf = vsp1_wpf_create(vsp1, i);
341 if (IS_ERR(wpf)) {
342 ret = PTR_ERR(wpf);
343 goto done;
344 }
345
346 vsp1->wpf[i] = wpf;
347 list_add_tail(&wpf->entity.list_dev, &vsp1->entities);
9d40637a 348
5aa2eb3c 349 if (vsp1->info->uapi) {
f2ed459d 350 struct vsp1_video *video = vsp1_video_create(vsp1, wpf);
9d40637a 351
f2ed459d
LP
352 if (IS_ERR(video)) {
353 ret = PTR_ERR(video);
354 goto done;
355 }
356
357 list_add_tail(&video->list, &vsp1->videos);
358 wpf->entity.sink = &video->video.entity;
359 }
26e0ca22
LP
360 }
361
7213fe7e
JMC
362 /* Register all subdevs. */
363 list_for_each_entry(entity, &vsp1->entities, list_dev) {
364 ret = v4l2_device_register_subdev(&vsp1->v4l2_dev,
365 &entity->subdev);
366 if (ret < 0)
367 goto done;
368 }
369
26e0ca22 370 /* Create links. */
5aa2eb3c 371 if (vsp1->info->uapi)
f3af9572
LP
372 ret = vsp1_uapi_create_links(vsp1);
373 else
374 ret = vsp1_drm_create_links(vsp1);
a07dcc53
LP
375 if (ret < 0)
376 goto done;
26e0ca22 377
f3af9572
LP
378 /* Register subdev nodes if the userspace API is enabled or initialize
379 * the DRM pipeline otherwise.
380 */
aa380ea0 381 if (vsp1->info->uapi)
f2ed459d 382 ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev);
aa380ea0 383 else
f3af9572
LP
384 ret = vsp1_drm_init(vsp1);
385 if (ret < 0)
386 goto done;
9832e155
JMC
387
388 ret = media_device_register(mdev);
26e0ca22
LP
389
390done:
391 if (ret < 0)
392 vsp1_destroy_entities(vsp1);
393
394 return ret;
395}
396
1517b039 397int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index)
26e0ca22 398{
1517b039 399 unsigned int timeout;
26e0ca22
LP
400 u32 status;
401
26e0ca22 402 status = vsp1_read(vsp1, VI6_STATUS);
1517b039
TS
403 if (!(status & VI6_STATUS_SYS_ACT(index)))
404 return 0;
26e0ca22 405
1517b039
TS
406 vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(index));
407 for (timeout = 10; timeout > 0; --timeout) {
408 status = vsp1_read(vsp1, VI6_STATUS);
409 if (!(status & VI6_STATUS_SYS_ACT(index)))
410 break;
26e0ca22 411
1517b039
TS
412 usleep_range(1000, 2000);
413 }
26e0ca22 414
1517b039
TS
415 if (!timeout) {
416 dev_err(vsp1->dev, "failed to reset wpf.%u\n", index);
417 return -ETIMEDOUT;
418 }
26e0ca22 419
1517b039
TS
420 return 0;
421}
26e0ca22 422
1517b039
TS
423static int vsp1_device_init(struct vsp1_device *vsp1)
424{
425 unsigned int i;
426 int ret;
427
428 /* Reset any channel that might be running. */
5aa2eb3c 429 for (i = 0; i < vsp1->info->wpf_count; ++i) {
1517b039
TS
430 ret = vsp1_reset_wpf(vsp1, i);
431 if (ret < 0)
432 return ret;
26e0ca22
LP
433 }
434
435 vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
436 (8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
437
5aa2eb3c 438 for (i = 0; i < vsp1->info->rpf_count; ++i)
26e0ca22
LP
439 vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
440
5aa2eb3c 441 for (i = 0; i < vsp1->info->uds_count; ++i)
26e0ca22
LP
442 vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
443
444 vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
445 vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED);
446 vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED);
447 vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED);
448 vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED);
449 vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED);
450
451 vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
452 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
453 vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
454 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
455
c2dd2513 456 vsp1_dlm_setup(vsp1);
1517b039 457
26e0ca22
LP
458 return 0;
459}
460
461/*
462 * vsp1_device_get - Acquire the VSP1 device
463 *
464 * Increment the VSP1 reference count and initialize the device if the first
465 * reference is taken.
466 *
4c16d6a0 467 * Return 0 on success or a negative error code otherwise.
26e0ca22 468 */
4c16d6a0 469int vsp1_device_get(struct vsp1_device *vsp1)
26e0ca22 470{
4c16d6a0 471 int ret = 0;
26e0ca22
LP
472
473 mutex_lock(&vsp1->lock);
474 if (vsp1->ref_count > 0)
475 goto done;
476
4fc78784 477 ret = clk_prepare_enable(vsp1->clock);
4c16d6a0 478 if (ret < 0)
26e0ca22 479 goto done;
26e0ca22
LP
480
481 ret = vsp1_device_init(vsp1);
482 if (ret < 0) {
4fc78784 483 clk_disable_unprepare(vsp1->clock);
26e0ca22
LP
484 goto done;
485 }
486
487done:
4c16d6a0 488 if (!ret)
26e0ca22
LP
489 vsp1->ref_count++;
490
491 mutex_unlock(&vsp1->lock);
4c16d6a0 492 return ret;
26e0ca22
LP
493}
494
495/*
496 * vsp1_device_put - Release the VSP1 device
497 *
498 * Decrement the VSP1 reference count and cleanup the device if the last
499 * reference is released.
500 */
501void vsp1_device_put(struct vsp1_device *vsp1)
502{
503 mutex_lock(&vsp1->lock);
504
505 if (--vsp1->ref_count == 0)
4fc78784 506 clk_disable_unprepare(vsp1->clock);
26e0ca22
LP
507
508 mutex_unlock(&vsp1->lock);
509}
510
511/* -----------------------------------------------------------------------------
512 * Power Management
513 */
514
515#ifdef CONFIG_PM_SLEEP
516static int vsp1_pm_suspend(struct device *dev)
517{
518 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
519
520 WARN_ON(mutex_is_locked(&vsp1->lock));
521
522 if (vsp1->ref_count == 0)
523 return 0;
524
139c9286
SF
525 vsp1_pipelines_suspend(vsp1);
526
4fc78784 527 clk_disable_unprepare(vsp1->clock);
139c9286 528
26e0ca22
LP
529 return 0;
530}
531
532static int vsp1_pm_resume(struct device *dev)
533{
534 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
535
536 WARN_ON(mutex_is_locked(&vsp1->lock));
537
139c9286 538 if (vsp1->ref_count == 0)
26e0ca22
LP
539 return 0;
540
139c9286
SF
541 clk_prepare_enable(vsp1->clock);
542
543 vsp1_pipelines_resume(vsp1);
544
545 return 0;
26e0ca22
LP
546}
547#endif
548
549static const struct dev_pm_ops vsp1_pm_ops = {
550 SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume)
551};
552
553/* -----------------------------------------------------------------------------
554 * Platform Driver
555 */
556
5aa2eb3c
LP
557static const struct vsp1_device_info vsp1_device_infos[] = {
558 {
559 .version = VI6_IP_VERSION_MODEL_VSPS_H2,
560 .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
561 .rpf_count = 5,
562 .uds_count = 3,
563 .wpf_count = 4,
564 .num_bru_inputs = 4,
565 .uapi = true,
566 }, {
567 .version = VI6_IP_VERSION_MODEL_VSPR_H2,
568 .features = VSP1_HAS_BRU | VSP1_HAS_SRU,
569 .rpf_count = 5,
570 .uds_count = 1,
571 .wpf_count = 4,
572 .num_bru_inputs = 4,
573 .uapi = true,
574 }, {
575 .version = VI6_IP_VERSION_MODEL_VSPD_GEN2,
576 .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT,
577 .rpf_count = 4,
578 .uds_count = 1,
579 .wpf_count = 4,
580 .num_bru_inputs = 4,
581 .uapi = true,
582 }, {
583 .version = VI6_IP_VERSION_MODEL_VSPS_M2,
584 .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU,
585 .rpf_count = 5,
586 .uds_count = 3,
587 .wpf_count = 4,
588 .num_bru_inputs = 4,
589 .uapi = true,
590 }, {
591 .version = VI6_IP_VERSION_MODEL_VSPI_GEN3,
592 .features = VSP1_HAS_LUT | VSP1_HAS_SRU,
593 .rpf_count = 1,
594 .uds_count = 1,
595 .wpf_count = 1,
596 .uapi = true,
597 }, {
598 .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3,
599 .features = VSP1_HAS_BRU,
600 .rpf_count = 5,
601 .wpf_count = 1,
602 .num_bru_inputs = 5,
603 .uapi = true,
604 }, {
605 .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3,
606 .features = VSP1_HAS_BRU | VSP1_HAS_LUT,
607 .rpf_count = 5,
608 .wpf_count = 1,
609 .num_bru_inputs = 5,
610 .uapi = true,
611 }, {
612 .version = VI6_IP_VERSION_MODEL_VSPD_GEN3,
94d48e56 613 .features = VSP1_HAS_BRU | VSP1_HAS_LIF,
5aa2eb3c
LP
614 .rpf_count = 5,
615 .wpf_count = 2,
616 .num_bru_inputs = 5,
617 },
618};
0b82fb95 619
26e0ca22
LP
620static int vsp1_probe(struct platform_device *pdev)
621{
622 struct vsp1_device *vsp1;
623 struct resource *irq;
624 struct resource *io;
5aa2eb3c 625 unsigned int i;
7f2d50f8 626 u32 version;
26e0ca22
LP
627 int ret;
628
629 vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL);
630 if (vsp1 == NULL)
631 return -ENOMEM;
632
633 vsp1->dev = &pdev->dev;
634 mutex_init(&vsp1->lock);
635 INIT_LIST_HEAD(&vsp1->entities);
9d40637a 636 INIT_LIST_HEAD(&vsp1->videos);
26e0ca22 637
26e0ca22
LP
638 /* I/O, IRQ and clock resources */
639 io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
640 vsp1->mmio = devm_ioremap_resource(&pdev->dev, io);
cbec6d3a
MCC
641 if (IS_ERR(vsp1->mmio))
642 return PTR_ERR(vsp1->mmio);
26e0ca22
LP
643
644 vsp1->clock = devm_clk_get(&pdev->dev, NULL);
645 if (IS_ERR(vsp1->clock)) {
646 dev_err(&pdev->dev, "failed to get clock\n");
647 return PTR_ERR(vsp1->clock);
648 }
649
650 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
651 if (!irq) {
652 dev_err(&pdev->dev, "missing IRQ\n");
653 return -EINVAL;
654 }
655
656 ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler,
657 IRQF_SHARED, dev_name(&pdev->dev), vsp1);
658 if (ret < 0) {
659 dev_err(&pdev->dev, "failed to request IRQ\n");
660 return ret;
661 }
662
7f2d50f8
LP
663 /* Configure device parameters based on the version register. */
664 ret = clk_prepare_enable(vsp1->clock);
665 if (ret < 0)
666 return ret;
667
668 version = vsp1_read(vsp1, VI6_IP_VERSION);
669 clk_disable_unprepare(vsp1->clock);
670
5aa2eb3c
LP
671 for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
672 if ((version & VI6_IP_VERSION_MODEL_MASK) ==
673 vsp1_device_infos[i].version) {
674 vsp1->info = &vsp1_device_infos[i];
675 break;
676 }
677 }
7f2d50f8 678
5aa2eb3c
LP
679 if (!vsp1->info) {
680 dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version);
681 return -ENXIO;
7f2d50f8
LP
682 }
683
5aa2eb3c
LP
684 dev_dbg(&pdev->dev, "IP version 0x%08x\n", version);
685
26e0ca22
LP
686 /* Instanciate entities */
687 ret = vsp1_create_entities(vsp1);
688 if (ret < 0) {
689 dev_err(&pdev->dev, "failed to create entities\n");
690 return ret;
691 }
692
693 platform_set_drvdata(pdev, vsp1);
694
695 return 0;
696}
697
698static int vsp1_remove(struct platform_device *pdev)
699{
700 struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
701
702 vsp1_destroy_entities(vsp1);
703
704 return 0;
705}
706
0b82fb95
LP
707static const struct of_device_id vsp1_of_match[] = {
708 { .compatible = "renesas,vsp1" },
7f2d50f8 709 { .compatible = "renesas,vsp2" },
0b82fb95
LP
710 { },
711};
712
26e0ca22
LP
713static struct platform_driver vsp1_platform_driver = {
714 .probe = vsp1_probe,
715 .remove = vsp1_remove,
716 .driver = {
26e0ca22
LP
717 .name = "vsp1",
718 .pm = &vsp1_pm_ops,
0b82fb95 719 .of_match_table = vsp1_of_match,
26e0ca22
LP
720 },
721};
722
723module_platform_driver(vsp1_platform_driver);
724
725MODULE_ALIAS("vsp1");
726MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
727MODULE_DESCRIPTION("Renesas VSP1 Driver");
728MODULE_LICENSE("GPL");
This page took 0.19929 seconds and 5 git commands to generate.