1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/device.h>
15#include <linux/slab.h>
16
17#include <media/media-entity.h>
18#include <media/v4l2-subdev.h>
19#include <media/vsp1.h>
20
21#include "vsp1.h"
22#include "vsp1_bru.h"
23#include "vsp1_dl.h"
24#include "vsp1_drm.h"
25#include "vsp1_lif.h"
26#include "vsp1_pipe.h"
27#include "vsp1_rwpf.h"
28
29
30
31
32
33
34void vsp1_drm_display_start(struct vsp1_device *vsp1)
35{
36 vsp1_dlm_irq_display_start(vsp1->drm->pipe.output->dlm);
37}
38
39
40
41
42
43int vsp1_du_init(struct device *dev)
44{
45 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
46
47 if (!vsp1)
48 return -EPROBE_DEFER;
49
50 return 0;
51}
52EXPORT_SYMBOL_GPL(vsp1_du_init);
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg)
72{
73 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
74 struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
75 struct vsp1_bru *bru = vsp1->bru;
76 struct v4l2_subdev_format format;
77 unsigned int i;
78 int ret;
79
80 if (!cfg) {
81
82
83
84
85 ret = vsp1_pipeline_stop(pipe);
86 if (ret == -ETIMEDOUT)
87 dev_err(vsp1->dev, "DRM pipeline stop timeout\n");
88
89 media_pipeline_stop(&pipe->output->entity.subdev.entity);
90
91 for (i = 0; i < bru->entity.source_pad; ++i) {
92 vsp1->drm->inputs[i].enabled = false;
93 bru->inputs[i].rpf = NULL;
94 pipe->inputs[i] = NULL;
95 }
96
97 pipe->num_inputs = 0;
98
99 vsp1_dlm_reset(pipe->output->dlm);
100 vsp1_device_put(vsp1);
101
102 dev_dbg(vsp1->dev, "%s: pipeline disabled\n", __func__);
103
104 return 0;
105 }
106
107 dev_dbg(vsp1->dev, "%s: configuring LIF with format %ux%u\n",
108 __func__, cfg->width, cfg->height);
109
110
111
112
113
114 memset(&format, 0, sizeof(format));
115 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
116
117 for (i = 0; i < bru->entity.source_pad; ++i) {
118 format.pad = i;
119
120 format.format.width = cfg->width;
121 format.format.height = cfg->height;
122 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
123 format.format.field = V4L2_FIELD_NONE;
124
125 ret = v4l2_subdev_call(&bru->entity.subdev, pad,
126 set_fmt, NULL, &format);
127 if (ret < 0)
128 return ret;
129
130 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
131 __func__, format.format.width, format.format.height,
132 format.format.code, i);
133 }
134
135 format.pad = bru->entity.source_pad;
136 format.format.width = cfg->width;
137 format.format.height = cfg->height;
138 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
139 format.format.field = V4L2_FIELD_NONE;
140
141 ret = v4l2_subdev_call(&bru->entity.subdev, pad, set_fmt, NULL,
142 &format);
143 if (ret < 0)
144 return ret;
145
146 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
147 __func__, format.format.width, format.format.height,
148 format.format.code, i);
149
150 format.pad = RWPF_PAD_SINK;
151 ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, set_fmt, NULL,
152 &format);
153 if (ret < 0)
154 return ret;
155
156 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on WPF0 sink\n",
157 __func__, format.format.width, format.format.height,
158 format.format.code);
159
160 format.pad = RWPF_PAD_SOURCE;
161 ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, get_fmt, NULL,
162 &format);
163 if (ret < 0)
164 return ret;
165
166 dev_dbg(vsp1->dev, "%s: got format %ux%u (%x) on WPF0 source\n",
167 __func__, format.format.width, format.format.height,
168 format.format.code);
169
170 format.pad = LIF_PAD_SINK;
171 ret = v4l2_subdev_call(&vsp1->lif->entity.subdev, pad, set_fmt, NULL,
172 &format);
173 if (ret < 0)
174 return ret;
175
176 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on LIF sink\n",
177 __func__, format.format.width, format.format.height,
178 format.format.code);
179
180
181
182
183
184 if (format.format.width != cfg->width ||
185 format.format.height != cfg->height ||
186 format.format.code != MEDIA_BUS_FMT_ARGB8888_1X32) {
187 dev_dbg(vsp1->dev, "%s: format mismatch\n", __func__);
188 return -EPIPE;
189 }
190
191
192
193
194
195
196
197
198 ret = vsp1_device_get(vsp1);
199 if (ret < 0)
200 return ret;
201
202 ret = media_pipeline_start(&pipe->output->entity.subdev.entity,
203 &pipe->pipe);
204 if (ret < 0) {
205 dev_dbg(vsp1->dev, "%s: pipeline start failed\n", __func__);
206 vsp1_device_put(vsp1);
207 return ret;
208 }
209
210 dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
211
212 return 0;
213}
214EXPORT_SYMBOL_GPL(vsp1_du_setup_lif);
215
216
217
218
219
220void vsp1_du_atomic_begin(struct device *dev)
221{
222 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
223 struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
224
225 vsp1->drm->num_inputs = pipe->num_inputs;
226}
227EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin);
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index,
259 const struct vsp1_du_atomic_config *cfg)
260{
261 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
262 const struct vsp1_format_info *fmtinfo;
263 struct vsp1_rwpf *rpf;
264
265 if (rpf_index >= vsp1->info->rpf_count)
266 return -EINVAL;
267
268 rpf = vsp1->rpf[rpf_index];
269
270 if (!cfg) {
271 dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__,
272 rpf_index);
273
274 vsp1->drm->inputs[rpf_index].enabled = false;
275 return 0;
276 }
277
278 dev_dbg(vsp1->dev,
279 "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n",
280 __func__, rpf_index,
281 cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height,
282 cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height,
283 cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1],
284 &cfg->mem[2], cfg->zpos);
285
286
287
288
289
290 fmtinfo = vsp1_get_format_info(vsp1, cfg->pixelformat);
291 if (!fmtinfo) {
292 dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n",
293 cfg->pixelformat);
294 return -EINVAL;
295 }
296
297 rpf->fmtinfo = fmtinfo;
298 rpf->format.num_planes = fmtinfo->planes;
299 rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
300 rpf->format.plane_fmt[1].bytesperline = cfg->pitch;
301 rpf->alpha = cfg->alpha;
302
303 rpf->mem.addr[0] = cfg->mem[0];
304 rpf->mem.addr[1] = cfg->mem[1];
305 rpf->mem.addr[2] = cfg->mem[2];
306
307 vsp1->drm->inputs[rpf_index].crop = cfg->src;
308 vsp1->drm->inputs[rpf_index].compose = cfg->dst;
309 vsp1->drm->inputs[rpf_index].zpos = cfg->zpos;
310 vsp1->drm->inputs[rpf_index].enabled = true;
311
312 return 0;
313}
314EXPORT_SYMBOL_GPL(vsp1_du_atomic_update);
315
316static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1,
317 struct vsp1_rwpf *rpf, unsigned int bru_input)
318{
319 struct v4l2_subdev_selection sel;
320 struct v4l2_subdev_format format;
321 const struct v4l2_rect *crop;
322 int ret;
323
324
325
326
327
328 crop = &vsp1->drm->inputs[rpf->entity.index].crop;
329
330 memset(&format, 0, sizeof(format));
331 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
332 format.pad = RWPF_PAD_SINK;
333 format.format.width = crop->width + crop->left;
334 format.format.height = crop->height + crop->top;
335 format.format.code = rpf->fmtinfo->mbus;
336 format.format.field = V4L2_FIELD_NONE;
337
338 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
339 &format);
340 if (ret < 0)
341 return ret;
342
343 dev_dbg(vsp1->dev,
344 "%s: set format %ux%u (%x) on RPF%u sink\n",
345 __func__, format.format.width, format.format.height,
346 format.format.code, rpf->entity.index);
347
348 memset(&sel, 0, sizeof(sel));
349 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
350 sel.pad = RWPF_PAD_SINK;
351 sel.target = V4L2_SEL_TGT_CROP;
352 sel.r = *crop;
353
354 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_selection, NULL,
355 &sel);
356 if (ret < 0)
357 return ret;
358
359 dev_dbg(vsp1->dev,
360 "%s: set selection (%u,%u)/%ux%u on RPF%u sink\n",
361 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
362 rpf->entity.index);
363
364
365
366
367
368 format.pad = RWPF_PAD_SOURCE;
369
370 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, get_fmt, NULL,
371 &format);
372 if (ret < 0)
373 return ret;
374
375 dev_dbg(vsp1->dev,
376 "%s: got format %ux%u (%x) on RPF%u source\n",
377 __func__, format.format.width, format.format.height,
378 format.format.code, rpf->entity.index);
379
380 format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32;
381
382 ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL,
383 &format);
384 if (ret < 0)
385 return ret;
386
387
388 format.pad = bru_input;
389
390 ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_fmt, NULL,
391 &format);
392 if (ret < 0)
393 return ret;
394
395 dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n",
396 __func__, format.format.width, format.format.height,
397 format.format.code, format.pad);
398
399 sel.pad = bru_input;
400 sel.target = V4L2_SEL_TGT_COMPOSE;
401 sel.r = vsp1->drm->inputs[rpf->entity.index].compose;
402
403 ret = v4l2_subdev_call(&vsp1->bru->entity.subdev, pad, set_selection,
404 NULL, &sel);
405 if (ret < 0)
406 return ret;
407
408 dev_dbg(vsp1->dev,
409 "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n",
410 __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height,
411 sel.pad);
412
413 return 0;
414}
415
416static unsigned int rpf_zpos(struct vsp1_device *vsp1, struct vsp1_rwpf *rpf)
417{
418 return vsp1->drm->inputs[rpf->entity.index].zpos;
419}
420
421
422
423
424
425void vsp1_du_atomic_flush(struct device *dev)
426{
427 struct vsp1_device *vsp1 = dev_get_drvdata(dev);
428 struct vsp1_pipeline *pipe = &vsp1->drm->pipe;
429 struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, };
430 struct vsp1_entity *entity;
431 struct vsp1_dl_list *dl;
432 unsigned long flags;
433 unsigned int i;
434 int ret;
435
436
437 dl = vsp1_dl_list_get(pipe->output->dlm);
438
439
440 pipe->num_inputs = 0;
441
442 for (i = 0; i < vsp1->info->rpf_count; ++i) {
443 struct vsp1_rwpf *rpf = vsp1->rpf[i];
444 unsigned int j;
445
446 if (!vsp1->drm->inputs[i].enabled) {
447 pipe->inputs[i] = NULL;
448 continue;
449 }
450
451 pipe->inputs[i] = rpf;
452
453
454 for (j = pipe->num_inputs++; j > 0; --j) {
455 if (rpf_zpos(vsp1, inputs[j-1]) <= rpf_zpos(vsp1, rpf))
456 break;
457 inputs[j] = inputs[j-1];
458 }
459
460 inputs[j] = rpf;
461 }
462
463
464 for (i = 0; i < vsp1->info->num_bru_inputs; ++i) {
465 struct vsp1_rwpf *rpf = inputs[i];
466
467 if (!rpf) {
468 vsp1->bru->inputs[i].rpf = NULL;
469 continue;
470 }
471
472 vsp1->bru->inputs[i].rpf = rpf;
473 rpf->bru_input = i;
474 rpf->entity.sink_pad = i;
475
476 dev_dbg(vsp1->dev, "%s: connecting RPF.%u to BRU:%u\n",
477 __func__, rpf->entity.index, i);
478
479 ret = vsp1_du_setup_rpf_pipe(vsp1, rpf, i);
480 if (ret < 0)
481 dev_err(vsp1->dev,
482 "%s: failed to setup RPF.%u\n",
483 __func__, rpf->entity.index);
484 }
485
486
487 list_for_each_entry(entity, &pipe->entities, list_pipe) {
488
489 if (entity->type == VSP1_ENTITY_RPF) {
490 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
491
492 if (!pipe->inputs[rpf->entity.index]) {
493 vsp1_dl_list_write(dl, entity->route->reg,
494 VI6_DPR_NODE_UNUSED);
495 continue;
496 }
497 }
498
499 vsp1_entity_route_setup(entity, pipe, dl);
500
501 if (entity->ops->configure) {
502 entity->ops->configure(entity, pipe, dl,
503 VSP1_ENTITY_PARAMS_INIT);
504 entity->ops->configure(entity, pipe, dl,
505 VSP1_ENTITY_PARAMS_RUNTIME);
506 entity->ops->configure(entity, pipe, dl,
507 VSP1_ENTITY_PARAMS_PARTITION);
508 }
509 }
510
511 vsp1_dl_list_commit(dl);
512
513
514 if (!vsp1->drm->num_inputs && pipe->num_inputs) {
515 vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
516 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, VI6_DISP_IRQ_ENB_DSTE);
517 spin_lock_irqsave(&pipe->irqlock, flags);
518 vsp1_pipeline_run(pipe);
519 spin_unlock_irqrestore(&pipe->irqlock, flags);
520 } else if (vsp1->drm->num_inputs && !pipe->num_inputs) {
521 vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
522 vsp1_pipeline_stop(pipe);
523 }
524}
525EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
526
527
528
529
530
531int vsp1_drm_create_links(struct vsp1_device *vsp1)
532{
533 const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
534 unsigned int i;
535 int ret;
536
537
538
539
540
541 if (!vsp1->bru || !vsp1->lif)
542 return -ENXIO;
543
544 for (i = 0; i < vsp1->info->rpf_count; ++i) {
545 struct vsp1_rwpf *rpf = vsp1->rpf[i];
546
547 ret = media_create_pad_link(&rpf->entity.subdev.entity,
548 RWPF_PAD_SOURCE,
549 &vsp1->bru->entity.subdev.entity,
550 i, flags);
551 if (ret < 0)
552 return ret;
553
554 rpf->entity.sink = &vsp1->bru->entity.subdev.entity;
555 rpf->entity.sink_pad = i;
556 }
557
558 ret = media_create_pad_link(&vsp1->bru->entity.subdev.entity,
559 vsp1->bru->entity.source_pad,
560 &vsp1->wpf[0]->entity.subdev.entity,
561 RWPF_PAD_SINK, flags);
562 if (ret < 0)
563 return ret;
564
565 vsp1->bru->entity.sink = &vsp1->wpf[0]->entity.subdev.entity;
566 vsp1->bru->entity.sink_pad = RWPF_PAD_SINK;
567
568 ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity,
569 RWPF_PAD_SOURCE,
570 &vsp1->lif->entity.subdev.entity,
571 LIF_PAD_SINK, flags);
572 if (ret < 0)
573 return ret;
574
575 return 0;
576}
577
578int vsp1_drm_init(struct vsp1_device *vsp1)
579{
580 struct vsp1_pipeline *pipe;
581 unsigned int i;
582
583 vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL);
584 if (!vsp1->drm)
585 return -ENOMEM;
586
587 pipe = &vsp1->drm->pipe;
588
589 vsp1_pipeline_init(pipe);
590
591
592 for (i = 0; i < vsp1->info->rpf_count; ++i) {
593 struct vsp1_rwpf *input = vsp1->rpf[i];
594
595 list_add_tail(&input->entity.list_pipe, &pipe->entities);
596 }
597
598 list_add_tail(&vsp1->bru->entity.list_pipe, &pipe->entities);
599 list_add_tail(&vsp1->wpf[0]->entity.list_pipe, &pipe->entities);
600 list_add_tail(&vsp1->lif->entity.list_pipe, &pipe->entities);
601
602 pipe->bru = &vsp1->bru->entity;
603 pipe->lif = &vsp1->lif->entity;
604 pipe->output = vsp1->wpf[0];
605 pipe->output->pipe = pipe;
606
607 return 0;
608}
609
610void vsp1_drm_cleanup(struct vsp1_device *vsp1)
611{
612}
613