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