1
2
3
4
5
6
7
8
9
10
11#include <drm/drmP.h>
12#include <drm/drm_atomic.h>
13#include <drm/drm_atomic_helper.h>
14#include <drm/drm_crtc.h>
15#include <drm/drm_fb_cma_helper.h>
16#include <drm/drm_fourcc.h>
17#include <drm/drm_gem_cma_helper.h>
18#include <drm/drm_modeset_helper_vtables.h>
19#include <linux/clk.h>
20#include <linux/component.h>
21#include <linux/dma/xilinx_frmbuf.h>
22#include <linux/gpio/consumer.h>
23#include <linux/of.h>
24#include <linux/of_dma.h>
25#include <linux/of_address.h>
26#include <linux/of_irq.h>
27#include <linux/dmaengine.h>
28#include "xlnx_drv.h"
29#include "xlnx_crtc.h"
30
31
32#define XVMIX_AP_CTRL 0x00000
33#define XVMIX_GIE 0x00004
34#define XVMIX_IER 0x00008
35#define XVMIX_ISR 0x0000c
36#define XVMIX_WIDTH_DATA 0x00010
37#define XVMIX_HEIGHT_DATA 0x00018
38#define XVMIX_BACKGROUND_Y_R_DATA 0x00028
39#define XVMIX_BACKGROUND_U_G_DATA 0x00030
40#define XVMIX_BACKGROUND_V_B_DATA 0x00038
41#define XVMIX_LAYERENABLE_DATA 0x00040
42#define XVMIX_LAYERALPHA_0_DATA 0x00100
43#define XVMIX_LAYERSTARTX_0_DATA 0x00108
44#define XVMIX_LAYERSTARTY_0_DATA 0x00110
45#define XVMIX_LAYERWIDTH_0_DATA 0x00118
46#define XVMIX_LAYERSTRIDE_0_DATA 0x00120
47#define XVMIX_LAYERHEIGHT_0_DATA 0x00128
48#define XVMIX_LAYERSCALE_0_DATA 0x00130
49#define XVMIX_LAYERVIDEOFORMAT_0_DATA 0x00138
50#define XVMIX_LAYER1_BUF1_V_DATA 0x00240
51#define XVMIX_LAYER1_BUF2_V_DATA 0x0024c
52#define XVMIX_LOGOSTARTX_DATA 0x01000
53#define XVMIX_LOGOSTARTY_DATA 0x01008
54#define XVMIX_LOGOWIDTH_DATA 0x01010
55#define XVMIX_LOGOHEIGHT_DATA 0x01018
56#define XVMIX_LOGOSCALEFACTOR_DATA 0x01020
57#define XVMIX_LOGOALPHA_DATA 0x01028
58#define XVMIX_LOGOCLRKEYMIN_R_DATA 0x01030
59#define XVMIX_LOGOCLRKEYMIN_G_DATA 0x01038
60#define XVMIX_LOGOCLRKEYMIN_B_DATA 0x01040
61#define XVMIX_LOGOCLRKEYMAX_R_DATA 0x01048
62#define XVMIX_LOGOCLRKEYMAX_G_DATA 0x01050
63#define XVMIX_LOGOCLRKEYMAX_B_DATA 0x01058
64#define XVMIX_LOGOR_V_BASE 0x10000
65#define XVMIX_LOGOR_V_HIGH 0x10fff
66#define XVMIX_LOGOG_V_BASE 0x20000
67#define XVMIX_LOGOG_V_HIGH 0x20fff
68#define XVMIX_LOGOB_V_BASE 0x30000
69#define XVMIX_LOGOB_V_HIGH 0x30fff
70#define XVMIX_LOGOA_V_BASE 0x40000
71#define XVMIX_LOGOA_V_HIGH 0x40fff
72
73
74#define XVMIX_LOGO_EN BIT(15)
75#define XVMIX_MASK_ENABLE_ALL_LAYERS (GENMASK(8, 0) | XVMIX_LOGO_EN)
76#define XVMIX_MASK_DISABLE_ALL_LAYERS 0x0
77#define XVMIX_REG_OFFSET 0x100
78#define XVMIX_MASTER_LAYER_IDX 0x0
79#define XVMIX_LOGO_LAYER_IDX 0x1
80#define XVMIX_DISP_MAX_WIDTH 4096
81#define XVMIX_DISP_MAX_HEIGHT 2160
82#define XVMIX_MAX_LAYERS 10
83#define XVMIX_MAX_BPC 16
84#define XVMIX_ALPHA_MIN 0
85#define XVMIX_ALPHA_MAX 256
86#define XVMIX_LAYER_WIDTH_MIN 64
87#define XVMIX_LAYER_HEIGHT_MIN 64
88#define XVMIX_LOGO_LAYER_WIDTH_MIN 32
89#define XVMIX_LOGO_LAYER_HEIGHT_MIN 32
90#define XVMIX_LOGO_LAYER_WIDTH_MAX 256
91#define XVMIX_LOGO_LAYER_HEIGHT_MAX 256
92#define XVMIX_IRQ_DONE_MASK BIT(0)
93#define XVMIX_GIE_EN_MASK BIT(0)
94#define XVMIX_AP_EN_MASK BIT(0)
95#define XVMIX_AP_RST_MASK BIT(7)
96#define XVMIX_MAX_NUM_SUB_PLANES 4
97#define XVMIX_SCALE_FACTOR_1X 0
98#define XVMIX_SCALE_FACTOR_2X 1
99#define XVMIX_SCALE_FACTOR_4X 2
100#define XVMIX_SCALE_FACTOR_INVALID 3
101#define XVMIX_BASE_ALIGN 8
102
103
104static const u32 color_table[] = {
105 DRM_FORMAT_BGR888,
106 DRM_FORMAT_RGB888,
107 DRM_FORMAT_XBGR2101010,
108 DRM_FORMAT_XRGB8888,
109 DRM_FORMAT_RGBA8888,
110 DRM_FORMAT_ABGR8888,
111 DRM_FORMAT_ARGB8888,
112 DRM_FORMAT_XBGR8888,
113 DRM_FORMAT_YUYV,
114 DRM_FORMAT_UYVY,
115 DRM_FORMAT_AYUV,
116 DRM_FORMAT_NV12,
117 DRM_FORMAT_NV16,
118 DRM_FORMAT_Y8,
119 DRM_FORMAT_Y10,
120 DRM_FORMAT_XVUY2101010,
121 DRM_FORMAT_VUY888,
122 DRM_FORMAT_XVUY8888,
123 DRM_FORMAT_XV15,
124 DRM_FORMAT_XV20,
125};
126
127
128#define to_mixer_hw(p) (&((p)->mixer->mixer_hw))
129#define to_xlnx_crtc(x) container_of(x, struct xlnx_crtc, crtc)
130#define to_xlnx_plane(x) container_of(x, struct xlnx_mix_plane, base)
131#define to_xlnx_mixer(x) container_of(x, struct xlnx_mix, crtc)
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147enum xlnx_mix_layer_id {
148 XVMIX_LAYER_MASTER = 0,
149 XVMIX_LAYER_1,
150 XVMIX_LAYER_2,
151 XVMIX_LAYER_3,
152 XVMIX_LAYER_4,
153 XVMIX_LAYER_5,
154 XVMIX_LAYER_6,
155 XVMIX_LAYER_7,
156 XVMIX_LAYER_8,
157 XVMIX_LAYER_LOGO,
158 XVMIX_LAYER_ALL
159};
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198struct xlnx_mix_layer_data {
199 struct {
200 u32 vid_fmt;
201 bool can_alpha;
202 bool can_scale;
203 bool is_streaming;
204 u32 max_width;
205 u32 max_height;
206 u32 min_width;
207 u32 min_height;
208 } hw_config;
209
210 struct {
211 u64 buff_addr1;
212 u64 buff_addr2;
213 u32 x_pos;
214 u32 y_pos;
215 u32 width;
216 u32 height;
217 u32 stride;
218 u32 alpha;
219 bool is_active;
220 u32 scale_fact;
221 } layer_regs;
222
223 enum xlnx_mix_layer_id id;
224};
225
226
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
254struct xlnx_mix_hw {
255 void __iomem *base;
256 bool logo_layer_en;
257 bool logo_pixel_alpha_enabled;
258 u32 max_layer_width;
259 u32 max_layer_height;
260 u32 max_logo_layer_width;
261 u32 max_logo_layer_height;
262 u32 max_layers;
263 u32 bg_layer_bpc;
264 u32 dma_addr_size;
265 u32 ppc;
266 int irq;
267 u64 bg_color;
268 struct xlnx_mix_layer_data *layer_data;
269 u32 layer_cnt;
270 struct gpio_desc *reset_gpio;
271 void (*intrpt_handler_fn)(void *);
272 void *intrpt_data;
273};
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304struct xlnx_mix {
305 struct xlnx_mix_hw mixer_hw;
306 struct platform_device *master;
307 struct xlnx_crtc crtc;
308 struct xlnx_mix_plane *drm_primary_layer;
309 struct xlnx_mix_plane *hw_master_layer;
310 struct xlnx_mix_plane *hw_logo_layer;
311 struct xlnx_mix_plane *planes;
312 u32 num_planes;
313 u32 max_width;
314 u32 max_height;
315 u32 max_cursor_width;
316 u32 max_cursor_height;
317 struct drm_property *alpha_prop;
318 struct drm_property *scale_prop;
319 struct drm_property *bg_color;
320 struct drm_device *drm;
321 struct clk *pixel_clock;
322 bool pixel_clock_enabled;
323 int dpms;
324 struct drm_pending_vblank_event *event;
325};
326
327
328
329
330
331
332
333
334
335struct xlnx_mix_plane_dma {
336 struct dma_chan *chan;
337 struct dma_interleaved_template xt;
338 struct data_chunk sgl[1];
339 bool is_active;
340};
341
342
343
344
345
346
347
348
349
350
351
352
353struct xlnx_mix_plane {
354 struct drm_plane base;
355 struct xlnx_mix_layer_data *mixer_layer;
356 struct xlnx_mix *mixer;
357 struct xlnx_mix_plane_dma dma[XVMIX_MAX_NUM_SUB_PLANES];
358 int id;
359 int dpms;
360 u32 format;
361};
362
363static inline void reg_writel(void __iomem *base, int offset, u32 val)
364{
365 writel(val, base + offset);
366}
367
368static inline void reg_writeq(void __iomem *base, int offset, u64 val)
369{
370 writel(upper_32_bits(val), base + offset);
371 writel(lower_32_bits(val), base + offset + 4);
372}
373
374static inline u32 reg_readl(void __iomem *base, int offset)
375{
376 return readl(base + offset);
377}
378
379
380
381
382
383
384
385static void xlnx_mix_intrpt_enable_done(struct xlnx_mix_hw *mixer)
386{
387 u32 curr_val = reg_readl(mixer->base, XVMIX_IER);
388
389
390 reg_writel(mixer->base, XVMIX_IER, curr_val | XVMIX_IRQ_DONE_MASK);
391 reg_writel(mixer->base, XVMIX_GIE, XVMIX_GIE_EN_MASK);
392}
393
394
395
396
397
398
399
400static void xlnx_mix_intrpt_disable(struct xlnx_mix_hw *mixer)
401{
402 u32 curr_val = reg_readl(mixer->base, XVMIX_IER);
403
404 reg_writel(mixer->base, XVMIX_IER, curr_val & (~XVMIX_IRQ_DONE_MASK));
405 reg_writel(mixer->base, XVMIX_GIE, 0);
406}
407
408
409
410
411
412
413
414static void xlnx_mix_start(struct xlnx_mix_hw *mixer)
415{
416 u32 val;
417
418 val = XVMIX_AP_RST_MASK | XVMIX_AP_EN_MASK;
419 reg_writel(mixer->base, XVMIX_AP_CTRL, val);
420}
421
422
423
424
425
426
427
428static void xlnx_mix_stop(struct xlnx_mix_hw *mixer)
429{
430 reg_writel(mixer->base, XVMIX_AP_CTRL, 0);
431}
432
433static inline uint32_t xlnx_mix_get_intr_status(struct xlnx_mix_hw *mixer)
434{
435 return reg_readl(mixer->base, XVMIX_ISR) & XVMIX_IRQ_DONE_MASK;
436}
437
438static inline void xlnx_mix_clear_intr_status(struct xlnx_mix_hw *mixer,
439 uint32_t intr)
440{
441 reg_writel(mixer->base, XVMIX_ISR, intr);
442}
443
444
445
446
447
448
449
450
451
452
453static struct xlnx_mix_layer_data *
454xlnx_mix_get_layer_data(struct xlnx_mix_hw *mixer, enum xlnx_mix_layer_id id)
455{
456 u32 i;
457 struct xlnx_mix_layer_data *layer_data;
458
459 for (i = 0; i <= (mixer->layer_cnt - 1); i++) {
460 layer_data = &mixer->layer_data[i];
461 if (layer_data->id == id)
462 return layer_data;
463 }
464 return NULL;
465}
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480static int xlnx_mix_set_active_area(struct xlnx_mix_hw *mixer,
481 u32 hactive, u32 vactive)
482{
483 struct xlnx_mix_layer_data *ld =
484 xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_MASTER);
485
486 if (hactive > ld->hw_config.max_width ||
487 vactive > ld->hw_config.max_height) {
488 DRM_ERROR("Invalid layer dimention\n");
489 return -EINVAL;
490 }
491
492 reg_writel(mixer->base, XVMIX_HEIGHT_DATA, vactive);
493 reg_writel(mixer->base, XVMIX_WIDTH_DATA, hactive);
494 ld->layer_regs.width = hactive;
495 ld->layer_regs.height = vactive;
496
497 return 0;
498}
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514static bool is_window_valid(struct xlnx_mix_hw *mixer, u32 x_pos, u32 y_pos,
515 u32 width, u32 height, u32 scale)
516{
517 struct xlnx_mix_layer_data *master_layer;
518 int scale_factor[3] = {1, 2, 4};
519
520 master_layer = xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_MASTER);
521
522
523 if (scale < XVMIX_SCALE_FACTOR_INVALID) {
524 width *= scale_factor[scale];
525 height *= scale_factor[scale];
526 }
527
528
529 if (((x_pos + width) <= master_layer->layer_regs.width) &&
530 ((y_pos + height) <= master_layer->layer_regs.height))
531 return true;
532
533 DRM_ERROR("Requested plane dimensions can't be set\n");
534 return false;
535}
536
537
538
539
540
541
542
543
544
545
546
547static void xlnx_mix_layer_enable(struct xlnx_mix_hw *mixer,
548 enum xlnx_mix_layer_id id)
549{
550 struct xlnx_mix_layer_data *layer_data;
551 u32 curr_state;
552
553
554
555
556
557
558 layer_data = xlnx_mix_get_layer_data(mixer, id);
559 if (!layer_data) {
560 DRM_ERROR("Invalid layer id %d\n", id);
561 return;
562 }
563 if (!layer_data->layer_regs.is_active)
564 return;
565
566
567 if (id == XVMIX_LAYER_ALL) {
568 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA,
569 XVMIX_MASK_ENABLE_ALL_LAYERS);
570
571 } else if ((id < mixer->layer_cnt) ||
572 ((id == XVMIX_LAYER_LOGO) && mixer->logo_layer_en)) {
573 curr_state = reg_readl(mixer->base, XVMIX_LAYERENABLE_DATA);
574 if (id == XVMIX_LAYER_LOGO)
575 curr_state |= XVMIX_LOGO_EN;
576 else
577 curr_state |= BIT(id);
578 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA, curr_state);
579 } else {
580 DRM_ERROR("Can't enable requested layer %d\n", id);
581 }
582}
583
584
585
586
587
588
589
590static void xlnx_mix_disp_layer_enable(struct xlnx_mix_plane *plane)
591{
592 struct xlnx_mix_hw *mixer_hw;
593 struct xlnx_mix_layer_data *l_data;
594 u32 id;
595
596 if (!plane)
597 return;
598 mixer_hw = to_mixer_hw(plane);
599 l_data = plane->mixer_layer;
600 id = l_data->id;
601 if (id < XVMIX_LAYER_MASTER || id > XVMIX_LAYER_LOGO) {
602 DRM_DEBUG_KMS("Attempt to activate invalid layer: %d\n", id);
603 return;
604 }
605 if (id == XVMIX_LAYER_MASTER && !l_data->hw_config.is_streaming)
606 return;
607
608 xlnx_mix_layer_enable(mixer_hw, id);
609}
610
611
612
613
614
615
616
617
618
619
620
621static void xlnx_mix_layer_disable(struct xlnx_mix_hw *mixer,
622 enum xlnx_mix_layer_id id)
623{
624 u32 num_layers, curr_state;
625
626 num_layers = mixer->layer_cnt;
627
628 if (id == XVMIX_LAYER_ALL) {
629 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA,
630 XVMIX_MASK_DISABLE_ALL_LAYERS);
631 } else if ((id < num_layers) ||
632 ((id == XVMIX_LAYER_LOGO) && (mixer->logo_layer_en))) {
633 curr_state = reg_readl(mixer->base, XVMIX_LAYERENABLE_DATA);
634 if (id == XVMIX_LAYER_LOGO)
635 curr_state &= ~XVMIX_LOGO_EN;
636 else
637 curr_state &= ~(BIT(id));
638 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA, curr_state);
639 } else {
640 DRM_ERROR("Can't disable requested layer %d\n", id);
641 }
642}
643
644
645
646
647
648
649
650static void xlnx_mix_disp_layer_disable(struct xlnx_mix_plane *plane)
651{
652 struct xlnx_mix_hw *mixer_hw;
653 u32 layer_id;
654
655 if (plane)
656 mixer_hw = to_mixer_hw(plane);
657 else
658 return;
659 layer_id = plane->mixer_layer->id;
660 if (layer_id < XVMIX_LAYER_MASTER || layer_id > XVMIX_LAYER_LOGO)
661 return;
662
663 xlnx_mix_layer_disable(mixer_hw, layer_id);
664}
665
666static int xlnx_mix_mark_layer_inactive(struct xlnx_mix_plane *plane)
667{
668 if (!plane || !plane->mixer_layer)
669 return -ENODEV;
670
671 plane->mixer_layer->layer_regs.is_active = false;
672
673 return 0;
674}
675
676
677static void xlnx_mix_plane_commit(struct drm_plane *base_plane)
678{
679 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
680 struct dma_async_tx_descriptor *desc;
681 enum dma_ctrl_flags flags;
682 unsigned int i;
683
684
685 xilinx_xdma_drm_config(plane->dma[0].chan, plane->format);
686 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++) {
687 struct xlnx_mix_plane_dma *dma = &plane->dma[i];
688
689 if (dma->chan && dma->is_active) {
690 flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
691 desc = dmaengine_prep_interleaved_dma(dma->chan,
692 &dma->xt,
693 flags);
694 if (!desc) {
695 DRM_ERROR("failed to prepare DMA descriptor\n");
696 return;
697 }
698 dmaengine_submit(desc);
699 dma_async_issue_pending(dma->chan);
700 }
701 }
702}
703
704static int xlnx_mix_plane_get_max_width(struct drm_plane *base_plane)
705{
706 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
707
708 return plane->mixer->max_width;
709}
710
711static int xlnx_mix_plane_get_max_height(struct drm_plane *base_plane)
712{
713 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
714
715 return plane->mixer->max_height;
716}
717
718static int xlnx_mix_plane_get_max_cursor_width(struct drm_plane *base_plane)
719{
720 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
721
722 return plane->mixer->max_cursor_width;
723}
724
725static int xlnx_mix_plane_get_max_cursor_height(struct drm_plane *base_plane)
726{
727 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
728
729 return plane->mixer->max_cursor_height;
730}
731
732static int xlnx_mix_crtc_get_max_width(struct xlnx_crtc *crtc)
733{
734 return xlnx_mix_plane_get_max_width(crtc->crtc.primary);
735}
736
737static int xlnx_mix_crtc_get_max_height(struct xlnx_crtc *crtc)
738{
739 return xlnx_mix_plane_get_max_height(crtc->crtc.primary);
740}
741
742static unsigned int xlnx_mix_crtc_get_max_cursor_width(struct xlnx_crtc *crtc)
743{
744 return xlnx_mix_plane_get_max_cursor_width(crtc->crtc.primary);
745}
746
747static unsigned int xlnx_mix_crtc_get_max_cursor_height(struct xlnx_crtc *crtc)
748{
749 return xlnx_mix_plane_get_max_cursor_height(crtc->crtc.primary);
750}
751
752
753
754
755
756
757
758
759
760static uint32_t xlnx_mix_crtc_get_format(struct xlnx_crtc *crtc)
761{
762 struct xlnx_mix_plane *plane = to_xlnx_plane(crtc->crtc.primary);
763
764 return plane->format;
765}
766
767
768
769
770
771
772
773
774
775static unsigned int xlnx_mix_crtc_get_align(struct xlnx_crtc *crtc)
776{
777 struct xlnx_mix_plane *plane = to_xlnx_plane(crtc->crtc.primary);
778 struct xlnx_mix *m = plane->mixer;
779
780 return XVMIX_BASE_ALIGN * m->mixer_hw.ppc;
781}
782
783
784
785
786
787
788
789
790
791
792
793static void xlnx_mix_attach_plane_prop(struct xlnx_mix_plane *plane)
794{
795 struct drm_mode_object *base = &plane->base.base;
796 struct xlnx_mix *mixer = plane->mixer;
797
798 if (plane->mixer_layer->hw_config.can_scale)
799 drm_object_attach_property(base, mixer->scale_prop,
800 XVMIX_SCALE_FACTOR_1X);
801 if (plane->mixer_layer->hw_config.can_alpha)
802 drm_object_attach_property(base, mixer->alpha_prop,
803 XVMIX_ALPHA_MAX);
804}
805
806static int xlnx_mix_mark_layer_active(struct xlnx_mix_plane *plane)
807{
808 if (!plane->mixer_layer)
809 return -ENODEV;
810 plane->mixer_layer->layer_regs.is_active = true;
811
812 return 0;
813}
814
815static bool xlnx_mix_isfmt_support(u32 format)
816{
817 int i;
818
819 for (i = 0; i < ARRAY_SIZE(color_table); i++) {
820 if (format == color_table[i])
821 return true;
822 }
823 return false;
824}
825
826
827
828
829
830
831
832
833
834
835
836
837
838static int xlnx_mix_get_layer_scaling(struct xlnx_mix_hw *mixer,
839 enum xlnx_mix_layer_id id)
840{
841 int scale_factor = 0;
842 u32 reg;
843 struct xlnx_mix_layer_data *l_data = xlnx_mix_get_layer_data(mixer, id);
844
845 switch (id) {
846 case XVMIX_LAYER_LOGO:
847 if (mixer->logo_layer_en) {
848 reg = XVMIX_LOGOSCALEFACTOR_DATA;
849 scale_factor = reg_readl(mixer->base, reg);
850 l_data->layer_regs.scale_fact = scale_factor;
851 }
852 break;
853
854 default:
855 if (id < XVMIX_LAYER_LOGO && l_data->hw_config.can_scale) {
856 reg = XVMIX_LAYERSCALE_0_DATA + (id * XVMIX_REG_OFFSET);
857 scale_factor = reg_readl(mixer->base, reg);
858 l_data->layer_regs.scale_fact = scale_factor;
859 }
860 break;
861 }
862 return scale_factor;
863}
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881static int xlnx_mix_set_layer_window(struct xlnx_mix_hw *mixer,
882 enum xlnx_mix_layer_id id, u32 x_pos,
883 u32 y_pos, u32 width, u32 height,
884 u32 stride)
885{
886 struct xlnx_mix_layer_data *l_data;
887 u32 scale = 0;
888 int status = -EINVAL;
889 u32 x_reg, y_reg, w_reg, h_reg, s_reg;
890 u32 off;
891
892 l_data = xlnx_mix_get_layer_data(mixer, id);
893 if (!l_data)
894 return status;
895
896 scale = xlnx_mix_get_layer_scaling(mixer, id);
897 if (!is_window_valid(mixer, x_pos, y_pos, width, height, scale))
898 return status;
899
900 switch (id) {
901 case XVMIX_LAYER_LOGO:
902 if (!(mixer->logo_layer_en &&
903 width <= l_data->hw_config.max_width &&
904 height <= l_data->hw_config.max_height &&
905 height >= l_data->hw_config.min_height &&
906 width >= l_data->hw_config.min_width))
907 return status;
908
909 x_reg = XVMIX_LOGOSTARTX_DATA;
910 y_reg = XVMIX_LOGOSTARTY_DATA;
911 w_reg = XVMIX_LOGOWIDTH_DATA;
912 h_reg = XVMIX_LOGOHEIGHT_DATA;
913 reg_writel(mixer->base, x_reg, x_pos);
914 reg_writel(mixer->base, y_reg, y_pos);
915 reg_writel(mixer->base, w_reg, width);
916 reg_writel(mixer->base, h_reg, height);
917 l_data->layer_regs.x_pos = x_pos;
918 l_data->layer_regs.y_pos = y_pos;
919 l_data->layer_regs.width = width;
920 l_data->layer_regs.height = height;
921 status = 0;
922 break;
923
924 default:
925
926 if (!(id < mixer->layer_cnt &&
927 width <= l_data->hw_config.max_width &&
928 width >= l_data->hw_config.min_width))
929 return status;
930 x_reg = XVMIX_LAYERSTARTX_0_DATA;
931 y_reg = XVMIX_LAYERSTARTY_0_DATA;
932 w_reg = XVMIX_LAYERWIDTH_0_DATA;
933 h_reg = XVMIX_LAYERHEIGHT_0_DATA;
934 s_reg = XVMIX_LAYERSTRIDE_0_DATA;
935
936 off = id * XVMIX_REG_OFFSET;
937 reg_writel(mixer->base, (x_reg + off), x_pos);
938 reg_writel(mixer->base, (y_reg + off), y_pos);
939 reg_writel(mixer->base, (w_reg + off), width);
940 reg_writel(mixer->base, (h_reg + off), height);
941 l_data->layer_regs.x_pos = x_pos;
942 l_data->layer_regs.y_pos = y_pos;
943 l_data->layer_regs.width = width;
944 l_data->layer_regs.height = height;
945
946 if (!l_data->hw_config.is_streaming)
947 reg_writel(mixer->base, (s_reg + off), stride);
948 status = 0;
949 break;
950 }
951 return status;
952}
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971static int xlnx_mix_set_layer_dimensions(struct xlnx_mix_plane *plane,
972 u32 crtc_x, u32 crtc_y,
973 u32 width, u32 height, u32 stride)
974{
975 struct xlnx_mix *mixer = plane->mixer;
976 struct xlnx_mix_hw *mixer_hw = to_mixer_hw(plane);
977 struct xlnx_mix_layer_data *layer_data;
978 enum xlnx_mix_layer_id layer_id;
979 int ret = 0;
980
981 layer_data = plane->mixer_layer;
982 layer_id = layer_data->id;
983 if (layer_data->layer_regs.height != height ||
984 layer_data->layer_regs.width != width) {
985 if (mixer->drm_primary_layer == plane)
986 xlnx_mix_layer_disable(mixer_hw, XVMIX_LAYER_MASTER);
987
988 xlnx_mix_layer_disable(mixer_hw, layer_id);
989 }
990 if (mixer->drm_primary_layer == plane) {
991 crtc_x = 0;
992 crtc_y = 0;
993 ret = xlnx_mix_set_active_area(mixer_hw, width, height);
994 if (ret)
995 return ret;
996 xlnx_mix_layer_enable(mixer_hw, XVMIX_LAYER_MASTER);
997 }
998 if (layer_id != XVMIX_LAYER_MASTER && layer_id < XVMIX_LAYER_ALL) {
999 ret = xlnx_mix_set_layer_window(mixer_hw, layer_id, crtc_x,
1000 crtc_y, width, height, stride);
1001 if (ret)
1002 return ret;
1003 xlnx_mix_disp_layer_enable(plane);
1004 }
1005 return ret;
1006}
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022static int xlnx_mix_set_layer_scaling(struct xlnx_mix_hw *mixer,
1023 enum xlnx_mix_layer_id id, u32 scale)
1024{
1025 void __iomem *reg = mixer->base;
1026 struct xlnx_mix_layer_data *l_data;
1027 int status = 0;
1028 u32 x_pos, y_pos, width, height, offset;
1029
1030 l_data = xlnx_mix_get_layer_data(mixer, id);
1031 x_pos = l_data->layer_regs.x_pos;
1032 y_pos = l_data->layer_regs.y_pos;
1033 width = l_data->layer_regs.width;
1034 height = l_data->layer_regs.height;
1035
1036 if (!is_window_valid(mixer, x_pos, y_pos, width, height, scale))
1037 return -EINVAL;
1038
1039 switch (id) {
1040 case XVMIX_LAYER_LOGO:
1041 if (mixer->logo_layer_en) {
1042 reg_writel(reg, XVMIX_LOGOSCALEFACTOR_DATA, scale);
1043 l_data->layer_regs.scale_fact = scale;
1044 status = 0;
1045 }
1046 break;
1047
1048 default:
1049 if (id < mixer->layer_cnt && l_data->hw_config.can_scale) {
1050 offset = id * XVMIX_REG_OFFSET;
1051
1052 reg_writel(reg, (XVMIX_LAYERSCALE_0_DATA + offset),
1053 scale);
1054 l_data->layer_regs.scale_fact = scale;
1055 status = 0;
1056 }
1057 break;
1058 }
1059 return status;
1060}
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074static int xlnx_mix_set_layer_scale(struct xlnx_mix_plane *plane,
1075 uint64_t val)
1076{
1077 struct xlnx_mix_hw *mixer_hw = to_mixer_hw(plane);
1078 struct xlnx_mix_layer_data *layer = plane->mixer_layer;
1079 int ret;
1080
1081 if (!layer || !layer->hw_config.can_scale)
1082 return -ENODEV;
1083 if (val > XVMIX_SCALE_FACTOR_4X || val < XVMIX_SCALE_FACTOR_1X) {
1084 DRM_ERROR("Mixer layer scale value illegal.\n");
1085 return -EINVAL;
1086 }
1087 xlnx_mix_disp_layer_disable(plane);
1088 msleep(50);
1089 ret = xlnx_mix_set_layer_scaling(mixer_hw, layer->id, val);
1090 xlnx_mix_disp_layer_enable(plane);
1091
1092 return ret;
1093}
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109static int xlnx_mix_set_layer_alpha(struct xlnx_mix_hw *mixer,
1110 enum xlnx_mix_layer_id layer_id, u32 alpha)
1111{
1112 struct xlnx_mix_layer_data *layer_data;
1113 u32 reg;
1114 int status = -EINVAL;
1115
1116 layer_data = xlnx_mix_get_layer_data(mixer, layer_id);
1117 switch (layer_id) {
1118 case XVMIX_LAYER_LOGO:
1119 if (mixer->logo_layer_en) {
1120 reg = XVMIX_LOGOALPHA_DATA;
1121 reg_writel(mixer->base, reg, alpha);
1122 layer_data->layer_regs.alpha = alpha;
1123 status = 0;
1124 }
1125 break;
1126
1127 default:
1128 if (layer_id < mixer->layer_cnt &&
1129 layer_data->hw_config.can_alpha) {
1130 u32 offset = layer_id * XVMIX_REG_OFFSET;
1131
1132 reg = XVMIX_LAYERALPHA_0_DATA;
1133 reg_writel(mixer->base, (reg + offset), alpha);
1134 layer_data->layer_regs.alpha = alpha;
1135 status = 0;
1136 }
1137 break;
1138 }
1139 return status;
1140}
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151static int xlnx_mix_disp_set_layer_alpha(struct xlnx_mix_plane *plane,
1152 uint64_t val)
1153{
1154 struct xlnx_mix_hw *mixer_hw = to_mixer_hw(plane);
1155 struct xlnx_mix_layer_data *layer = plane->mixer_layer;
1156
1157 if (!layer || !layer->hw_config.can_alpha)
1158 return -ENODEV;
1159 if (val > XVMIX_ALPHA_MAX || val < XVMIX_ALPHA_MIN) {
1160 DRM_ERROR("Mixer layer alpha dts value illegal.\n");
1161 return -EINVAL;
1162 }
1163 return xlnx_mix_set_layer_alpha(mixer_hw, layer->id, val);
1164}
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177static int xlnx_mix_set_layer_buff_addr(struct xlnx_mix_hw *mixer,
1178 enum xlnx_mix_layer_id id,
1179 u64 luma_addr, u64 chroma_addr)
1180{
1181 struct xlnx_mix_layer_data *layer_data;
1182 u32 align, offset;
1183 u32 reg1, reg2;
1184
1185 if (id >= mixer->layer_cnt)
1186 return -EINVAL;
1187
1188
1189 align = mixer->ppc * 8;
1190 if ((luma_addr % align) != 0 || (chroma_addr % align) != 0)
1191 return -EINVAL;
1192
1193 offset = (id - 1) * XVMIX_REG_OFFSET;
1194 reg1 = XVMIX_LAYER1_BUF1_V_DATA + offset;
1195 reg2 = XVMIX_LAYER1_BUF2_V_DATA + offset;
1196 layer_data = &mixer->layer_data[id];
1197 if (mixer->dma_addr_size == 64 && sizeof(dma_addr_t) == 8) {
1198 reg_writeq(mixer->base, reg1, luma_addr);
1199 reg_writeq(mixer->base, reg2, chroma_addr);
1200 } else {
1201 reg_writel(mixer->base, reg1, (u32)luma_addr);
1202 reg_writel(mixer->base, reg2, (u32)chroma_addr);
1203 }
1204 layer_data->layer_regs.buff_addr1 = luma_addr;
1205 layer_data->layer_regs.buff_addr2 = chroma_addr;
1206
1207 return 0;
1208}
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221static void
1222xlnx_mix_hw_plane_dpms(struct xlnx_mix_plane *plane, int dpms)
1223{
1224 struct xlnx_mix *mixer;
1225
1226 if (!plane->mixer)
1227 return;
1228 mixer = plane->mixer;
1229 plane->dpms = dpms;
1230
1231 switch (dpms) {
1232 case DRM_MODE_DPMS_ON:
1233 xlnx_mix_disp_layer_enable(plane);
1234 break;
1235 default:
1236 xlnx_mix_mark_layer_inactive(plane);
1237 xlnx_mix_disp_layer_disable(plane);
1238
1239 if (mixer->alpha_prop)
1240 xlnx_mix_disp_set_layer_alpha(plane, XVMIX_ALPHA_MAX);
1241 if (mixer->scale_prop)
1242 xlnx_mix_set_layer_scale(plane, XVMIX_SCALE_FACTOR_1X);
1243 }
1244}
1245
1246static void xlnx_mix_plane_dpms(struct drm_plane *base_plane, int dpms)
1247{
1248 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1249 unsigned int i;
1250
1251 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
1252 DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);
1253
1254 if (plane->dpms == dpms)
1255 return;
1256 plane->dpms = dpms;
1257 switch (dpms) {
1258 case DRM_MODE_DPMS_ON:
1259
1260 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++)
1261 if (plane->dma[i].chan && plane->dma[i].is_active)
1262 dma_async_issue_pending(plane->dma[i].chan);
1263 xlnx_mix_hw_plane_dpms(plane, dpms);
1264 break;
1265 default:
1266 xlnx_mix_hw_plane_dpms(plane, dpms);
1267
1268 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++) {
1269 if (plane->dma[i].chan && plane->dma[i].is_active) {
1270 dmaengine_terminate_sync(plane->dma[i].chan);
1271 plane->dma[i].is_active = false;
1272 }
1273 }
1274 break;
1275 }
1276}
1277
1278static int
1279xlnx_mix_disp_plane_atomic_set_property(struct drm_plane *base_plane,
1280 struct drm_plane_state *state,
1281 struct drm_property *property, u64 val)
1282{
1283 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1284 struct xlnx_mix *mixer = plane->mixer;
1285
1286 if (property == mixer->alpha_prop)
1287 return xlnx_mix_disp_set_layer_alpha(plane, val);
1288 else if (property == mixer->scale_prop)
1289 return xlnx_mix_set_layer_scale(plane, val);
1290 else
1291 return -EINVAL;
1292 return 0;
1293}
1294
1295static int
1296xlnx_mix_disp_plane_atomic_get_property(struct drm_plane *base_plane,
1297 const struct drm_plane_state *state,
1298 struct drm_property *property,
1299 uint64_t *val)
1300{
1301 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1302 struct xlnx_mix *mixer = plane->mixer;
1303 struct xlnx_mix_hw *mixer_hw = to_mixer_hw(plane);
1304 u32 layer_id = plane->mixer_layer->id;
1305
1306 if (property == mixer->alpha_prop)
1307 *val = mixer_hw->layer_data[layer_id].layer_regs.alpha;
1308 else if (property == mixer->scale_prop)
1309 *val = mixer_hw->layer_data[layer_id].layer_regs.scale_fact;
1310 else
1311 return -EINVAL;
1312
1313 return 0;
1314}
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336static int
1337xlnx_mix_disp_plane_atomic_update_plane(struct drm_plane *plane,
1338 struct drm_crtc *crtc,
1339 struct drm_framebuffer *fb,
1340 int crtc_x, int crtc_y,
1341 unsigned int crtc_w,
1342 unsigned int crtc_h,
1343 uint32_t src_x, uint32_t src_y,
1344 uint32_t src_w, uint32_t src_h,
1345 struct drm_modeset_acquire_ctx *ctx)
1346{
1347 struct drm_atomic_state *state;
1348 struct drm_plane_state *plane_state;
1349 int ret = 0;
1350
1351 state = drm_atomic_state_alloc(plane->dev);
1352 if (!state)
1353 return -ENOMEM;
1354
1355 state->acquire_ctx = ctx;
1356 plane_state = drm_atomic_get_plane_state(state, plane);
1357 if (IS_ERR(plane_state)) {
1358 ret = PTR_ERR(plane_state);
1359 goto fail;
1360 }
1361
1362 ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
1363 if (ret != 0)
1364 goto fail;
1365
1366 drm_atomic_set_fb_for_plane(plane_state, fb);
1367 plane_state->crtc_x = crtc_x;
1368 plane_state->crtc_y = crtc_y;
1369 plane_state->crtc_w = crtc_w;
1370 plane_state->crtc_h = crtc_h;
1371 plane_state->src_x = src_x;
1372 plane_state->src_y = src_y;
1373 plane_state->src_w = src_w;
1374 plane_state->src_h = src_h;
1375
1376 if (plane == crtc->cursor)
1377 state->legacy_cursor_update = true;
1378
1379
1380 state->async_update = !drm_atomic_helper_async_check(plane->dev, state);
1381
1382 ret = drm_atomic_commit(state);
1383
1384fail:
1385 drm_atomic_state_put(state);
1386 return ret;
1387}
1388
1389static struct drm_plane_funcs xlnx_mix_plane_funcs = {
1390 .update_plane = xlnx_mix_disp_plane_atomic_update_plane,
1391 .disable_plane = drm_atomic_helper_disable_plane,
1392 .atomic_set_property = xlnx_mix_disp_plane_atomic_set_property,
1393 .atomic_get_property = xlnx_mix_disp_plane_atomic_get_property,
1394 .destroy = drm_plane_cleanup,
1395 .reset = drm_atomic_helper_plane_reset,
1396 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
1397 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
1398};
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415static int xlnx_mix_logo_load(struct xlnx_mix_hw *mixer, u32 logo_w, u32 logo_h,
1416 u8 *r_buf, u8 *g_buf, u8 *b_buf, u8 *a_buf)
1417{
1418 void __iomem *reg = mixer->base;
1419 struct xlnx_mix_layer_data *layer_data;
1420
1421 int x;
1422 u32 shift;
1423 u32 rword, gword, bword, aword;
1424 u32 pixel_cnt = logo_w * logo_h;
1425 u32 unaligned_pix_cnt = pixel_cnt % 4;
1426 u32 width, height, curr_x_pos, curr_y_pos;
1427 u32 rbase_addr, gbase_addr, bbase_addr, abase_addr;
1428
1429 layer_data = xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_LOGO);
1430 rword = 0;
1431 gword = 0;
1432 bword = 0;
1433 aword = 0;
1434
1435 if (!layer_data)
1436 return -ENODEV;
1437
1438
1439 if (unaligned_pix_cnt && mixer->logo_pixel_alpha_enabled)
1440 return -EINVAL;
1441
1442 if (!(mixer->logo_layer_en &&
1443 logo_w <= layer_data->hw_config.max_width &&
1444 logo_h <= layer_data->hw_config.max_height))
1445 return -EINVAL;
1446
1447 width = logo_w;
1448 height = logo_h;
1449 rbase_addr = XVMIX_LOGOR_V_BASE;
1450 gbase_addr = XVMIX_LOGOG_V_BASE;
1451 bbase_addr = XVMIX_LOGOB_V_BASE;
1452 abase_addr = XVMIX_LOGOA_V_BASE;
1453
1454 for (x = 0; x < pixel_cnt; x++) {
1455 shift = (x % 4) * 8;
1456 rword |= r_buf[x] << shift;
1457 gword |= g_buf[x] << shift;
1458 bword |= b_buf[x] << shift;
1459 if (mixer->logo_pixel_alpha_enabled)
1460 aword |= a_buf[x] << shift;
1461
1462 if (x % 4 == 3) {
1463 reg_writel(reg, (rbase_addr + (x - 3)), rword);
1464 reg_writel(reg, (gbase_addr + (x - 3)), gword);
1465 reg_writel(reg, (bbase_addr + (x - 3)), bword);
1466 if (mixer->logo_pixel_alpha_enabled)
1467 reg_writel(reg, (abase_addr + (x - 3)), aword);
1468 }
1469 }
1470
1471 curr_x_pos = layer_data->layer_regs.x_pos;
1472 curr_y_pos = layer_data->layer_regs.y_pos;
1473 return xlnx_mix_set_layer_window(mixer, XVMIX_LAYER_LOGO, curr_x_pos,
1474 curr_y_pos, logo_w, logo_h, 0);
1475}
1476
1477static int xlnx_mix_update_logo_img(struct xlnx_mix_plane *plane,
1478 struct drm_gem_cma_object *buffer,
1479 u32 src_w, u32 src_h)
1480{
1481 struct xlnx_mix_layer_data *logo_layer = plane->mixer_layer;
1482 size_t pixel_cnt = src_h * src_w;
1483
1484 u32 pix_cmp_cnt;
1485 u32 logo_cmp_cnt;
1486 bool per_pixel_alpha = false;
1487 u32 max_width = logo_layer->hw_config.max_width;
1488 u32 max_height = logo_layer->hw_config.max_height;
1489 u32 min_width = logo_layer->hw_config.min_width;
1490 u32 min_height = logo_layer->hw_config.min_height;
1491 u8 *r_data = NULL;
1492 u8 *g_data = NULL;
1493 u8 *b_data = NULL;
1494 u8 *a_data = NULL;
1495 size_t el_size = sizeof(u8);
1496 u8 *pixel_mem_data;
1497 int ret, i, j;
1498
1499
1500 if (logo_layer->id != XVMIX_LAYER_LOGO)
1501 return 0;
1502
1503 if (src_h > max_height || src_w > max_width ||
1504 src_h < min_height || src_w < min_width) {
1505 DRM_ERROR("Mixer logo/cursor layer dimensions illegal.\n");
1506 return -EINVAL;
1507 }
1508
1509 if (!xlnx_mix_isfmt_support(plane->mixer_layer->hw_config.vid_fmt)) {
1510 DRM_ERROR("DRM color format not supported for logo layer\n");
1511 return -EINVAL;
1512 }
1513 per_pixel_alpha = (logo_layer->hw_config.vid_fmt ==
1514 DRM_FORMAT_RGBA8888) ? true : false;
1515 r_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1516 g_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1517 b_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1518 if (per_pixel_alpha)
1519 a_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1520
1521 if (!r_data || !g_data || !b_data || (per_pixel_alpha && !a_data)) {
1522 DRM_ERROR("Unable to allocate memory for logo layer data\n");
1523 ret = -ENOMEM;
1524 goto free;
1525 }
1526 pix_cmp_cnt = per_pixel_alpha ? 4 : 3;
1527 logo_cmp_cnt = pixel_cnt * pix_cmp_cnt;
1528
1529
1530
1531 if ((phys_addr_t)buffer->vaddr == logo_layer->layer_regs.buff_addr1 &&
1532 src_w == logo_layer->layer_regs.width &&
1533 src_h == logo_layer->layer_regs.height)
1534 return 0;
1535
1536
1537 logo_layer->layer_regs.buff_addr1 = (phys_addr_t)buffer->vaddr;
1538 pixel_mem_data = (u8 *)(buffer->vaddr);
1539 for (i = 0, j = 0; j < pixel_cnt; j++) {
1540 if (per_pixel_alpha && a_data)
1541 a_data[j] = pixel_mem_data[i++];
1542
1543 b_data[j] = pixel_mem_data[i++];
1544 g_data[j] = pixel_mem_data[i++];
1545 r_data[j] = pixel_mem_data[i++];
1546 }
1547 ret = xlnx_mix_logo_load(to_mixer_hw(plane), src_w, src_h, r_data,
1548 g_data, b_data,
1549 per_pixel_alpha ? a_data : NULL);
1550free:
1551 kfree(r_data);
1552 kfree(g_data);
1553 kfree(b_data);
1554 kfree(a_data);
1555
1556 return ret;
1557}
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581static int xlnx_mix_set_plane(struct xlnx_mix_plane *plane,
1582 struct drm_framebuffer *fb,
1583 int crtc_x, int crtc_y,
1584 u32 src_x, u32 src_y,
1585 u32 src_w, u32 src_h)
1586{
1587 struct xlnx_mix_hw *mixer_hw;
1588 struct xlnx_mix *mixer;
1589 struct drm_gem_cma_object *luma_buffer;
1590 u32 luma_stride = fb->pitches[0];
1591 u64 luma_addr, chroma_addr = 0;
1592 u32 active_area_width;
1593 u32 active_area_height;
1594 enum xlnx_mix_layer_id layer_id;
1595 int ret;
1596 const struct drm_format_info *info = fb->format;
1597
1598 mixer = plane->mixer;
1599 mixer_hw = &mixer->mixer_hw;
1600 layer_id = plane->mixer_layer->id;
1601 active_area_width =
1602 mixer->drm_primary_layer->mixer_layer->layer_regs.width;
1603 active_area_height =
1604 mixer->drm_primary_layer->mixer_layer->layer_regs.height;
1605
1606 luma_buffer = drm_fb_cma_get_gem_obj(fb, 0);
1607 luma_addr = drm_fb_cma_get_gem_addr(fb, plane->base.state, 0);
1608 if (!luma_addr) {
1609 DRM_ERROR("%s failed to get luma paddr\n", __func__);
1610 return -EINVAL;
1611 }
1612
1613 if (info->num_planes > 1) {
1614 chroma_addr = drm_fb_cma_get_gem_addr(fb, plane->base.state, 1);
1615 if (!chroma_addr) {
1616 DRM_ERROR("failed to get chroma paddr\n");
1617 return -EINVAL;
1618 }
1619 }
1620 ret = xlnx_mix_mark_layer_active(plane);
1621 if (ret)
1622 return ret;
1623
1624 switch (layer_id) {
1625 case XVMIX_LAYER_LOGO:
1626 ret = xlnx_mix_update_logo_img(plane, luma_buffer,
1627 src_w, src_h);
1628 if (ret)
1629 break;
1630
1631 ret = xlnx_mix_set_layer_dimensions(plane, crtc_x, crtc_y,
1632 src_w, src_h, luma_stride);
1633 break;
1634
1635 case XVMIX_LAYER_MASTER:
1636 if (!plane->mixer_layer->hw_config.is_streaming)
1637 xlnx_mix_mark_layer_inactive(plane);
1638 if (mixer->drm_primary_layer == mixer->hw_master_layer) {
1639 xlnx_mix_layer_disable(mixer_hw, layer_id);
1640 ret = xlnx_mix_set_active_area(mixer_hw, src_w, src_h);
1641 if (ret)
1642 return ret;
1643 xlnx_mix_layer_enable(mixer_hw, layer_id);
1644
1645 } else if (src_w != active_area_width ||
1646 src_h != active_area_height) {
1647 DRM_ERROR("Invalid dimensions for mixer layer 0.\n");
1648 return -EINVAL;
1649 }
1650 break;
1651
1652 default:
1653 ret = xlnx_mix_set_layer_dimensions(plane, crtc_x, crtc_y,
1654 src_w, src_h, luma_stride);
1655 if (ret)
1656 break;
1657
1658 if (!plane->mixer_layer->hw_config.is_streaming)
1659 ret = xlnx_mix_set_layer_buff_addr
1660 (mixer_hw,
1661 plane->mixer_layer->id,
1662 luma_addr, chroma_addr);
1663 }
1664 return ret;
1665}
1666
1667
1668static int xlnx_mix_plane_mode_set(struct drm_plane *base_plane,
1669 struct drm_framebuffer *fb,
1670 int crtc_x, int crtc_y,
1671 unsigned int crtc_w, unsigned int crtc_h,
1672 u32 src_x, uint32_t src_y,
1673 u32 src_w, uint32_t src_h)
1674{
1675 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1676 const struct drm_format_info *info = fb->format;
1677 size_t i = 0;
1678 dma_addr_t luma_paddr;
1679 int ret;
1680 u32 stride;
1681
1682
1683 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
1684 DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n", src_w, crtc_x, src_h, crtc_y);
1685
1686
1687 for (; i < info->num_planes; i++) {
1688 unsigned int width = src_w / (i ? info->hsub : 1);
1689 unsigned int height = src_h / (i ? info->vsub : 1);
1690
1691 luma_paddr = drm_fb_cma_get_gem_addr(fb, base_plane->state, i);
1692 if (!luma_paddr) {
1693 DRM_ERROR("%s failed to get luma paddr\n", __func__);
1694 return -EINVAL;
1695 }
1696
1697 plane->dma[i].xt.numf = height;
1698 plane->dma[i].sgl[0].size =
1699 drm_format_plane_width_bytes(info, 0, width);
1700 plane->dma[i].sgl[0].icg = fb->pitches[0] -
1701 plane->dma[i].sgl[0].size;
1702 plane->dma[i].xt.src_start = luma_paddr;
1703 plane->dma[i].xt.frame_size = info->num_planes;
1704 plane->dma[i].xt.dir = DMA_MEM_TO_DEV;
1705 plane->dma[i].xt.src_sgl = true;
1706 plane->dma[i].xt.dst_sgl = false;
1707 plane->dma[i].is_active = true;
1708 }
1709
1710 for (; i < XVMIX_MAX_NUM_SUB_PLANES; i++)
1711 plane->dma[i].is_active = false;
1712
1713
1714
1715 if (plane->dma[0].chan && !plane->dma[1].chan && info->num_planes > 1) {
1716 stride = plane->dma[0].sgl[0].size + plane->dma[0].sgl[0].icg;
1717 plane->dma[0].sgl[0].src_icg = plane->dma[1].xt.src_start -
1718 plane->dma[0].xt.src_start -
1719 (plane->dma[0].xt.numf * stride);
1720 }
1721
1722 ret = xlnx_mix_set_plane(plane, fb, crtc_x, crtc_y, src_x, src_y,
1723 src_w, src_h);
1724 return ret;
1725}
1726
1727static int xlnx_mix_plane_prepare_fb(struct drm_plane *plane,
1728 struct drm_plane_state *new_state)
1729{
1730 return 0;
1731}
1732
1733static void xlnx_mix_plane_cleanup_fb(struct drm_plane *plane,
1734 struct drm_plane_state *old_state)
1735{
1736}
1737
1738static int xlnx_mix_plane_atomic_check(struct drm_plane *plane,
1739 struct drm_plane_state *state)
1740{
1741 return 0;
1742}
1743
1744static void xlnx_mix_plane_atomic_update(struct drm_plane *plane,
1745 struct drm_plane_state *old_state)
1746{
1747 int ret;
1748
1749 if (!plane->state->crtc || !plane->state->fb)
1750 return;
1751
1752 if (old_state->fb &&
1753 old_state->fb->format->format != plane->state->fb->format->format)
1754 xlnx_mix_plane_dpms(plane, DRM_MODE_DPMS_OFF);
1755
1756 ret = xlnx_mix_plane_mode_set(plane, plane->state->fb,
1757 plane->state->crtc_x,
1758 plane->state->crtc_y,
1759 plane->state->crtc_w,
1760 plane->state->crtc_h,
1761 plane->state->src_x >> 16,
1762 plane->state->src_y >> 16,
1763 plane->state->src_w >> 16,
1764 plane->state->src_h >> 16);
1765 if (ret) {
1766 DRM_ERROR("failed to mode-set a plane\n");
1767 return;
1768 }
1769
1770 xlnx_mix_plane_commit(plane);
1771
1772 xlnx_mix_plane_dpms(plane, DRM_MODE_DPMS_ON);
1773}
1774
1775static void xlnx_mix_plane_atomic_disable(struct drm_plane *plane,
1776 struct drm_plane_state *old_state)
1777{
1778 xlnx_mix_plane_dpms(plane, DRM_MODE_DPMS_OFF);
1779}
1780
1781static int xlnx_mix_plane_atomic_async_check(struct drm_plane *plane,
1782 struct drm_plane_state *state)
1783{
1784 return 0;
1785}
1786
1787static void
1788xlnx_mix_plane_atomic_async_update(struct drm_plane *plane,
1789 struct drm_plane_state *new_state)
1790{
1791 struct drm_plane_state *old_state =
1792 drm_atomic_get_old_plane_state(new_state->state, plane);
1793
1794
1795 drm_atomic_set_fb_for_plane(plane->state, new_state->fb);
1796 plane->state->crtc = new_state->crtc;
1797 plane->state->crtc_x = new_state->crtc_x;
1798 plane->state->crtc_y = new_state->crtc_y;
1799 plane->state->crtc_w = new_state->crtc_w;
1800 plane->state->crtc_h = new_state->crtc_h;
1801 plane->state->src_x = new_state->src_x;
1802 plane->state->src_y = new_state->src_y;
1803 plane->state->src_w = new_state->src_w;
1804 plane->state->src_h = new_state->src_h;
1805 plane->state->state = new_state->state;
1806
1807 xlnx_mix_plane_atomic_update(plane, old_state);
1808}
1809
1810static const struct drm_plane_helper_funcs xlnx_mix_plane_helper_funcs = {
1811 .prepare_fb = xlnx_mix_plane_prepare_fb,
1812 .cleanup_fb = xlnx_mix_plane_cleanup_fb,
1813 .atomic_check = xlnx_mix_plane_atomic_check,
1814 .atomic_update = xlnx_mix_plane_atomic_update,
1815 .atomic_disable = xlnx_mix_plane_atomic_disable,
1816 .atomic_async_check = xlnx_mix_plane_atomic_async_check,
1817 .atomic_async_update = xlnx_mix_plane_atomic_async_update,
1818};
1819
1820static int xlnx_mix_init_plane(struct xlnx_mix_plane *plane,
1821 unsigned int poss_crtcs,
1822 struct device_node *layer_node)
1823{
1824 struct xlnx_mix *mixer = plane->mixer;
1825 char name[16];
1826 enum drm_plane_type type;
1827 int ret, i;
1828
1829 plane->dpms = DRM_MODE_DPMS_OFF;
1830 type = DRM_PLANE_TYPE_OVERLAY;
1831
1832 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++) {
1833 snprintf(name, sizeof(name), "dma%d", i);
1834 plane->dma[i].chan = of_dma_request_slave_channel(layer_node,
1835 name);
1836 if (PTR_ERR(plane->dma[i].chan) == -ENODEV) {
1837 plane->dma[i].chan = NULL;
1838 continue;
1839 }
1840 if (IS_ERR(plane->dma[i].chan)) {
1841 DRM_ERROR("failed to request dma channel\n");
1842 ret = PTR_ERR(plane->dma[i].chan);
1843 plane->dma[i].chan = NULL;
1844 goto err_dma;
1845 }
1846 }
1847 if (!xlnx_mix_isfmt_support(plane->mixer_layer->hw_config.vid_fmt)) {
1848 DRM_ERROR("DRM color format not supported by mixer\n");
1849 ret = -ENODEV;
1850 goto err_init;
1851 }
1852 plane->format = plane->mixer_layer->hw_config.vid_fmt;
1853 if (plane == mixer->hw_logo_layer)
1854 type = DRM_PLANE_TYPE_CURSOR;
1855 if (plane == mixer->drm_primary_layer)
1856 type = DRM_PLANE_TYPE_PRIMARY;
1857
1858
1859 ret = drm_universal_plane_init(mixer->drm, &plane->base,
1860 poss_crtcs, &xlnx_mix_plane_funcs,
1861 &plane->format,
1862 1, NULL, type, NULL);
1863
1864 if (ret) {
1865 DRM_ERROR("failed to initialize plane\n");
1866 goto err_init;
1867 }
1868 drm_plane_helper_add(&plane->base, &xlnx_mix_plane_helper_funcs);
1869 of_node_put(layer_node);
1870
1871 return 0;
1872
1873err_init:
1874 xlnx_mix_disp_layer_disable(plane);
1875err_dma:
1876 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++)
1877 if (plane->dma[i].chan)
1878 dma_release_channel(plane->dma[i].chan);
1879
1880 of_node_put(layer_node);
1881 return ret;
1882}
1883
1884static int xlnx_mix_parse_dt_bg_video_fmt(struct device_node *node,
1885 struct xlnx_mix_hw *mixer_hw)
1886{
1887 struct device_node *layer_node;
1888 struct xlnx_mix_layer_data *layer;
1889 const char *vformat;
1890
1891 layer_node = of_get_child_by_name(node, "layer_0");
1892 layer = &mixer_hw->layer_data[XVMIX_MASTER_LAYER_IDX];
1893
1894
1895 layer->hw_config.can_alpha = false;
1896 layer->hw_config.can_scale = false;
1897 layer->hw_config.min_width = XVMIX_LAYER_WIDTH_MIN;
1898 layer->hw_config.min_height = XVMIX_LAYER_HEIGHT_MIN;
1899
1900 if (of_property_read_string(layer_node, "xlnx,vformat",
1901 &vformat)) {
1902 DRM_ERROR("No xlnx,vformat value for layer 0 in dts\n");
1903 return -EINVAL;
1904 }
1905 strcpy((char *)&layer->hw_config.vid_fmt, vformat);
1906 layer->hw_config.is_streaming =
1907 of_property_read_bool(layer_node, "xlnx,layer-streaming");
1908 if (of_property_read_u32(node, "xlnx,bpc", &mixer_hw->bg_layer_bpc)) {
1909 DRM_ERROR("Failed to get bits per component (bpc) prop\n");
1910 return -EINVAL;
1911 }
1912 if (of_property_read_u32(layer_node, "xlnx,layer-max-width",
1913 &layer->hw_config.max_width)) {
1914 DRM_ERROR("Failed to get screen width prop\n");
1915 return -EINVAL;
1916 }
1917 mixer_hw->max_layer_width = layer->hw_config.max_width;
1918 if (of_property_read_u32(layer_node, "xlnx,layer-max-height",
1919 &layer->hw_config.max_height)) {
1920 DRM_ERROR("Failed to get screen height prop\n");
1921 return -EINVAL;
1922 }
1923 mixer_hw->max_layer_height = layer->hw_config.max_height;
1924 layer->id = XVMIX_LAYER_MASTER;
1925
1926 return 0;
1927}
1928
1929static int xlnx_mix_parse_dt_logo_data(struct device_node *node,
1930 struct xlnx_mix_hw *mixer_hw)
1931{
1932 struct xlnx_mix_layer_data *layer_data;
1933 struct device_node *logo_node;
1934 u32 max_width, max_height;
1935
1936 logo_node = of_get_child_by_name(node, "logo");
1937 if (!logo_node) {
1938 DRM_ERROR("No logo node specified in device tree.\n");
1939 return -EINVAL;
1940 }
1941
1942 layer_data = &mixer_hw->layer_data[XVMIX_LOGO_LAYER_IDX];
1943
1944
1945 layer_data->hw_config.min_height = XVMIX_LOGO_LAYER_HEIGHT_MIN;
1946 layer_data->hw_config.min_width = XVMIX_LOGO_LAYER_WIDTH_MIN;
1947 layer_data->hw_config.is_streaming = false;
1948 layer_data->hw_config.vid_fmt = DRM_FORMAT_RGB888;
1949 layer_data->hw_config.can_alpha = true;
1950 layer_data->hw_config.can_scale = true;
1951 layer_data->layer_regs.buff_addr1 = 0;
1952 layer_data->layer_regs.buff_addr2 = 0;
1953 layer_data->id = XVMIX_LAYER_LOGO;
1954
1955 if (of_property_read_u32(logo_node, "xlnx,logo-width", &max_width)) {
1956 DRM_ERROR("Failed to get logo width prop\n");
1957 return -EINVAL;
1958 }
1959 if (max_width > XVMIX_LOGO_LAYER_WIDTH_MAX ||
1960 max_width < XVMIX_LOGO_LAYER_WIDTH_MIN) {
1961 DRM_ERROR("Illegal mixer logo layer width.\n");
1962 return -EINVAL;
1963 }
1964 layer_data->hw_config.max_width = max_width;
1965 mixer_hw->max_logo_layer_width = layer_data->hw_config.max_width;
1966
1967 if (of_property_read_u32(logo_node, "xlnx,logo-height", &max_height)) {
1968 DRM_ERROR("Failed to get logo height prop\n");
1969 return -EINVAL;
1970 }
1971 if (max_height > XVMIX_LOGO_LAYER_HEIGHT_MAX ||
1972 max_height < XVMIX_LOGO_LAYER_HEIGHT_MIN) {
1973 DRM_ERROR("Illegal mixer logo layer height.\n");
1974 return -EINVAL;
1975 }
1976 layer_data->hw_config.max_height = max_height;
1977 mixer_hw->max_logo_layer_height = layer_data->hw_config.max_height;
1978 mixer_hw->logo_pixel_alpha_enabled =
1979 of_property_read_bool(logo_node, "xlnx,logo-pixel-alpha");
1980 if (mixer_hw->logo_pixel_alpha_enabled)
1981 layer_data->hw_config.vid_fmt = DRM_FORMAT_RGBA8888;
1982
1983 return 0;
1984}
1985
1986static int xlnx_mix_dt_parse(struct device *dev, struct xlnx_mix *mixer)
1987{
1988 struct xlnx_mix_plane *planes;
1989 struct xlnx_mix_hw *mixer_hw;
1990 struct device_node *node;
1991 struct xlnx_mix_layer_data *l_data;
1992 struct resource res;
1993 int ret, l_cnt, i;
1994
1995 node = dev->of_node;
1996 mixer_hw = &mixer->mixer_hw;
1997 mixer->dpms = DRM_MODE_DPMS_OFF;
1998
1999 mixer_hw->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
2000 if (IS_ERR(mixer_hw->reset_gpio)) {
2001 ret = PTR_ERR(mixer_hw->reset_gpio);
2002 if (ret == -EPROBE_DEFER)
2003 dev_dbg(dev, "No gpio probed for mixer. Deferring\n");
2004 else
2005 dev_err(dev, "No reset gpio info from dts for mixer\n");
2006 return ret;
2007 }
2008 gpiod_set_raw_value(mixer_hw->reset_gpio, 0);
2009 gpiod_set_raw_value(mixer_hw->reset_gpio, 1);
2010
2011 ret = of_address_to_resource(node, 0, &res);
2012 if (ret) {
2013 dev_err(dev, "Invalid memory address for mixer %d\n", ret);
2014 return ret;
2015 }
2016
2017 mixer_hw->base = devm_ioremap_resource(dev, &res);
2018 if (IS_ERR(mixer_hw->base)) {
2019 dev_err(dev, "Failed to map io mem space for mixer\n");
2020 return PTR_ERR(mixer_hw->base);
2021 }
2022 ret = of_property_read_u32(node, "xlnx,num-layers",
2023 &mixer_hw->max_layers);
2024 if (ret) {
2025 dev_err(dev, "No xlnx,num-layers dts prop for mixer node\n");
2026 return ret;
2027 }
2028 if (mixer_hw->max_layers > XVMIX_MAX_LAYERS) {
2029 dev_err(dev, "Num layer nodes in device tree > mixer max\n");
2030 return -EINVAL;
2031 }
2032 ret = of_property_read_u32(node, "xlnx,dma-addr-width",
2033 &mixer_hw->dma_addr_size);
2034 if (ret) {
2035 dev_err(dev, "missing addr-width dts prop\n");
2036 return ret;
2037 }
2038 if (mixer_hw->dma_addr_size != 32 && mixer_hw->dma_addr_size != 64) {
2039 dev_err(dev, "invalid addr-width dts prop\n");
2040 return -EINVAL;
2041 }
2042 mixer_hw->logo_layer_en = of_property_read_bool(node,
2043 "xlnx,logo-layer");
2044 l_cnt = mixer_hw->max_layers + (mixer_hw->logo_layer_en ? 1 : 0);
2045 mixer_hw->layer_cnt = l_cnt;
2046
2047 l_data = devm_kzalloc(dev, sizeof(*l_data) * l_cnt, GFP_KERNEL);
2048 if (!l_data)
2049 return -ENOMEM;
2050 mixer_hw->layer_data = l_data;
2051
2052 planes = devm_kzalloc(dev, sizeof(*planes) * l_cnt, GFP_KERNEL);
2053 if (!planes)
2054 return -ENOMEM;
2055 mixer->planes = planes;
2056 mixer->num_planes = l_cnt;
2057 for (i = 0; i < mixer->num_planes; i++)
2058 mixer->planes[i].mixer = mixer;
2059
2060
2061 ret = xlnx_mix_parse_dt_bg_video_fmt(node, mixer_hw);
2062 if (ret)
2063 return ret;
2064
2065 ret = xlnx_mix_parse_dt_logo_data(node, mixer_hw);
2066 return ret;
2067 return 0;
2068}
2069
2070static int xlnx_mix_of_init_layer(struct device *dev, struct device_node *node,
2071 char *name, struct xlnx_mix_layer_data *layer,
2072 u32 max_width, struct xlnx_mix *mixer, int id)
2073{
2074 struct device_node *layer_node;
2075 const char *vformat;
2076 int ret;
2077
2078 layer_node = of_get_child_by_name(node, name);
2079 if (!layer_node)
2080 return -EINVAL;
2081
2082
2083 layer->hw_config.can_alpha = false;
2084 layer->hw_config.can_scale = false;
2085 layer->hw_config.is_streaming = false;
2086 layer->hw_config.max_width = max_width;
2087 layer->hw_config.min_width = XVMIX_LAYER_WIDTH_MIN;
2088 layer->hw_config.min_height = XVMIX_LAYER_HEIGHT_MIN;
2089 layer->hw_config.vid_fmt = 0;
2090 layer->id = 0;
2091 mixer->planes[id].mixer_layer = layer;
2092
2093 ret = of_property_read_u32(layer_node, "xlnx,layer-id", &layer->id);
2094 if (ret) {
2095 dev_err(dev, "xlnx,layer-id property not found\n");
2096 return ret;
2097 }
2098 if (layer->id < 1 || layer->id >= XVMIX_MAX_LAYERS) {
2099 dev_err(dev, "Mixer layer id %u in dts is out of legal range\n",
2100 layer->id);
2101 return -EINVAL;
2102 }
2103 ret = of_property_read_string(layer_node, "xlnx,vformat", &vformat);
2104 if (ret) {
2105 dev_err(dev, "No mixer layer vformat in dts for layer id %d\n",
2106 layer->id);
2107 return ret;
2108 }
2109
2110 strcpy((char *)&layer->hw_config.vid_fmt, vformat);
2111 layer->hw_config.can_scale =
2112 of_property_read_bool(layer_node, "xlnx,layer-scale");
2113 if (layer->hw_config.can_scale) {
2114 ret = of_property_read_u32(layer_node, "xlnx,layer-max-width",
2115 &layer->hw_config.max_width);
2116 if (ret) {
2117 dev_err(dev, "Mixer layer %d dts missing width prop.\n",
2118 layer->id);
2119 return ret;
2120 }
2121
2122 if (layer->hw_config.max_width > max_width) {
2123 dev_err(dev, "Illlegal Mixer layer %d width %d\n",
2124 layer->id, layer->hw_config.max_width);
2125 return -EINVAL;
2126 }
2127 }
2128 layer->hw_config.can_alpha =
2129 of_property_read_bool(layer_node, "xlnx,layer-alpha");
2130 layer->hw_config.is_streaming =
2131 of_property_read_bool(layer_node, "xlnx,layer-streaming");
2132 if (of_property_read_bool(layer_node, "xlnx,layer-primary")) {
2133 if (mixer->drm_primary_layer) {
2134 dev_err(dev,
2135 "More than one primary layer in mixer dts\n");
2136 return -EINVAL;
2137 }
2138 mixer->drm_primary_layer = &mixer->planes[id];
2139 }
2140 ret = xlnx_mix_init_plane(&mixer->planes[id], 1, layer_node);
2141 if (ret)
2142 dev_err(dev, "Unable to init drm mixer plane id = %u", id);
2143
2144 return ret;
2145}
2146
2147static irqreturn_t xlnx_mix_intr_handler(int irq, void *data)
2148{
2149 struct xlnx_mix_hw *mixer = data;
2150 u32 intr = xlnx_mix_get_intr_status(mixer);
2151
2152 if (!intr)
2153 return IRQ_NONE;
2154 if (mixer->intrpt_handler_fn)
2155 mixer->intrpt_handler_fn(mixer->intrpt_data);
2156 xlnx_mix_clear_intr_status(mixer, intr);
2157
2158 return IRQ_HANDLED;
2159}
2160
2161static void xlnx_mix_create_plane_properties(struct xlnx_mix *mixer)
2162{
2163 mixer->scale_prop = drm_property_create_range(mixer->drm, 0, "scale",
2164 XVMIX_SCALE_FACTOR_1X,
2165 XVMIX_SCALE_FACTOR_4X);
2166 mixer->alpha_prop = drm_property_create_range(mixer->drm, 0, "alpha",
2167 XVMIX_ALPHA_MIN,
2168 XVMIX_ALPHA_MAX);
2169}
2170
2171static int xlnx_mix_plane_create(struct device *dev, struct xlnx_mix *mixer)
2172{
2173 struct xlnx_mix_hw *mixer_hw;
2174 struct device_node *node, *layer_node;
2175 char name[20];
2176 struct xlnx_mix_layer_data *layer_data;
2177 int ret, i;
2178 int layer_idx;
2179
2180 node = dev->of_node;
2181 mixer_hw = &mixer->mixer_hw;
2182 xlnx_mix_create_plane_properties(mixer);
2183
2184 mixer->planes[XVMIX_MASTER_LAYER_IDX].mixer_layer =
2185 &mixer_hw->layer_data[XVMIX_MASTER_LAYER_IDX];
2186 mixer->planes[XVMIX_MASTER_LAYER_IDX].id = XVMIX_MASTER_LAYER_IDX;
2187 mixer->hw_master_layer = &mixer->planes[XVMIX_MASTER_LAYER_IDX];
2188
2189 if (mixer_hw->logo_layer_en) {
2190 mixer->planes[XVMIX_LOGO_LAYER_IDX].mixer_layer =
2191 &mixer_hw->layer_data[XVMIX_LOGO_LAYER_IDX];
2192 mixer->planes[XVMIX_LOGO_LAYER_IDX].id = XVMIX_LOGO_LAYER_IDX;
2193 mixer->hw_logo_layer = &mixer->planes[XVMIX_LOGO_LAYER_IDX];
2194 layer_node = of_get_child_by_name(node, "logo");
2195 ret = xlnx_mix_init_plane(&mixer->planes[XVMIX_LOGO_LAYER_IDX],
2196 1, layer_node);
2197 if (ret)
2198 return ret;
2199 }
2200 layer_idx = mixer_hw->logo_layer_en ? 2 : 1;
2201 for (i = 1; i < mixer_hw->max_layers; i++, layer_idx++) {
2202 snprintf(name, sizeof(name), "layer_%d", i);
2203 ret = xlnx_mix_of_init_layer(dev, node, name,
2204 &mixer_hw->layer_data[layer_idx],
2205 mixer_hw->max_layer_width,
2206 mixer, layer_idx);
2207 if (ret)
2208 return ret;
2209 }
2210
2211
2212
2213 if (!mixer->drm_primary_layer)
2214 mixer->drm_primary_layer = mixer->hw_master_layer;
2215 layer_node = of_get_child_by_name(node, "layer_0");
2216 ret = xlnx_mix_init_plane(&mixer->planes[XVMIX_MASTER_LAYER_IDX], 1,
2217 layer_node);
2218
2219 mixer_hw->irq = irq_of_parse_and_map(node, 0);
2220 if (mixer_hw->irq > 0) {
2221 ret = devm_request_irq(dev, mixer_hw->irq,
2222 xlnx_mix_intr_handler,
2223 IRQF_SHARED, "xlnx-mixer", mixer_hw);
2224 if (ret) {
2225 dev_err(dev, "Failed to request irq\n");
2226 return ret;
2227 }
2228 }
2229 ret = of_property_read_u32(node, "xlnx,ppc", &mixer_hw->ppc);
2230 if (ret) {
2231 dev_err(dev, "No xlnx,ppc property for mixer dts\n");
2232 return ret;
2233 }
2234
2235 mixer->max_width = XVMIX_DISP_MAX_WIDTH;
2236 mixer->max_height = XVMIX_DISP_MAX_HEIGHT;
2237 if (mixer->hw_logo_layer) {
2238 layer_data = &mixer_hw->layer_data[XVMIX_LOGO_LAYER_IDX];
2239 mixer->max_cursor_width = layer_data->hw_config.max_width;
2240 mixer->max_cursor_height = layer_data->hw_config.max_height;
2241 }
2242 return 0;
2243}
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254static void xlnx_mix_plane_restore(struct xlnx_mix *mixer)
2255{
2256 struct xlnx_mix_plane *plane;
2257 unsigned int i;
2258
2259 if (!mixer)
2260 return;
2261
2262
2263
2264
2265
2266 for (i = 0; i < mixer->num_planes; i++) {
2267 plane = &mixer->planes[i];
2268 if (!plane)
2269 continue;
2270 xlnx_mix_hw_plane_dpms(plane, DRM_MODE_DPMS_OFF);
2271 }
2272}
2273
2274
2275
2276
2277
2278
2279
2280
2281static void xlnx_mix_set_bkg_col(struct xlnx_mix_hw *mixer, u64 rgb_value)
2282{
2283 u32 bg_bpc = mixer->bg_layer_bpc;
2284 u32 bpc_mask_shift = XVMIX_MAX_BPC - bg_bpc;
2285 u32 val_mask = (GENMASK(15, 0) >> bpc_mask_shift);
2286 u16 b_val = (rgb_value >> (bg_bpc * 2)) & val_mask;
2287 u16 g_val = (rgb_value >> bg_bpc) & val_mask;
2288 u16 r_val = (rgb_value >> 0) & val_mask;
2289
2290
2291 reg_writel(mixer->base, XVMIX_BACKGROUND_Y_R_DATA, r_val);
2292 reg_writel(mixer->base, XVMIX_BACKGROUND_U_G_DATA, g_val);
2293 reg_writel(mixer->base, XVMIX_BACKGROUND_V_B_DATA, b_val);
2294 mixer->bg_color = rgb_value;
2295}
2296
2297
2298
2299
2300
2301
2302
2303static void xlnx_mix_reset(struct xlnx_mix *mixer)
2304{
2305 struct xlnx_mix_hw *mixer_hw = &mixer->mixer_hw;
2306
2307 gpiod_set_raw_value(mixer_hw->reset_gpio, 0);
2308 gpiod_set_raw_value(mixer_hw->reset_gpio, 1);
2309
2310 xlnx_mix_set_bkg_col(mixer_hw, mixer_hw->bg_color);
2311 xlnx_mix_plane_restore(mixer);
2312 xlnx_mix_intrpt_enable_done(&mixer->mixer_hw);
2313}
2314
2315static void xlnx_mix_dpms(struct xlnx_mix *mixer, int dpms)
2316{
2317 switch (dpms) {
2318 case DRM_MODE_DPMS_ON:
2319 xlnx_mix_start(&mixer->mixer_hw);
2320 break;
2321 default:
2322 xlnx_mix_stop(&mixer->mixer_hw);
2323 mdelay(50);
2324 xlnx_mix_reset(mixer);
2325 }
2326}
2327
2328
2329static void xlnx_mix_crtc_dpms(struct drm_crtc *base_crtc, int dpms)
2330{
2331 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2332 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2333 int ret;
2334
2335 DRM_DEBUG_KMS("dpms: %d\n", dpms);
2336 if (mixer->dpms == dpms)
2337 return;
2338 mixer->dpms = dpms;
2339
2340 switch (dpms) {
2341 case DRM_MODE_DPMS_ON:
2342 if (!mixer->pixel_clock_enabled) {
2343 ret = clk_prepare_enable(mixer->pixel_clock);
2344 if (ret) {
2345 DRM_ERROR("failed to enable a pixel clock\n");
2346 mixer->pixel_clock_enabled = false;
2347 }
2348 }
2349 mixer->pixel_clock_enabled = true;
2350
2351 xlnx_mix_dpms(mixer, dpms);
2352 xlnx_mix_plane_dpms(base_crtc->primary, dpms);
2353 break;
2354 default:
2355 xlnx_mix_plane_dpms(base_crtc->primary, dpms);
2356 xlnx_mix_dpms(mixer, dpms);
2357 if (mixer->pixel_clock_enabled) {
2358 clk_disable_unprepare(mixer->pixel_clock);
2359 mixer->pixel_clock_enabled = false;
2360 }
2361 break;
2362 }
2363}
2364
2365static void xlnx_mix_set_intr_handler(struct xlnx_mix *mixer,
2366 void (*intr_handler_fn)(void *),
2367 void *data)
2368{
2369 mixer->mixer_hw.intrpt_handler_fn = intr_handler_fn;
2370 mixer->mixer_hw.intrpt_data = data;
2371}
2372
2373static void xlnx_mix_crtc_vblank_handler(void *data)
2374{
2375 struct drm_crtc *base_crtc = data;
2376 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2377 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2378 struct drm_device *drm = base_crtc->dev;
2379 struct drm_pending_vblank_event *event;
2380 unsigned long flags;
2381
2382 drm_crtc_handle_vblank(base_crtc);
2383
2384 spin_lock_irqsave(&drm->event_lock, flags);
2385 event = mixer->event;
2386 mixer->event = NULL;
2387 if (event) {
2388 drm_crtc_send_vblank_event(base_crtc, event);
2389 drm_crtc_vblank_put(base_crtc);
2390 }
2391 spin_unlock_irqrestore(&drm->event_lock, flags);
2392}
2393
2394static int xlnx_mix_crtc_enable_vblank(struct drm_crtc *base_crtc)
2395{
2396 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2397 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2398
2399 xlnx_mix_set_intr_handler(mixer, xlnx_mix_crtc_vblank_handler,
2400 base_crtc);
2401 return 0;
2402}
2403
2404static void xlnx_mix_crtc_disable_vblank(struct drm_crtc *base_crtc)
2405{
2406 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2407 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2408
2409 mixer->mixer_hw.intrpt_handler_fn = NULL;
2410 mixer->mixer_hw.intrpt_data = NULL;
2411}
2412
2413static void xlnx_mix_crtc_destroy(struct drm_crtc *base_crtc)
2414{
2415 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2416 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2417
2418
2419 mixer->alpha_prop = NULL;
2420 mixer->scale_prop = NULL;
2421 mixer->bg_color = NULL;
2422 xlnx_mix_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF);
2423
2424 if (mixer->pixel_clock_enabled) {
2425 clk_disable_unprepare(mixer->pixel_clock);
2426 mixer->pixel_clock_enabled = false;
2427 }
2428 drm_crtc_cleanup(base_crtc);
2429}
2430
2431static int
2432xlnx_mix_disp_crtc_atomic_set_property(struct drm_crtc *crtc,
2433 struct drm_crtc_state *state,
2434 struct drm_property *property,
2435 uint64_t val)
2436{
2437 return 0;
2438}
2439
2440static int
2441xlnx_mix_disp_crtc_atomic_get_property(struct drm_crtc *crtc,
2442 const struct drm_crtc_state *state,
2443 struct drm_property *property,
2444 uint64_t *val)
2445{
2446 return 0;
2447}
2448
2449static struct drm_crtc_funcs xlnx_mix_crtc_funcs = {
2450 .destroy = xlnx_mix_crtc_destroy,
2451 .set_config = drm_atomic_helper_set_config,
2452 .page_flip = drm_atomic_helper_page_flip,
2453 .atomic_set_property = xlnx_mix_disp_crtc_atomic_set_property,
2454 .atomic_get_property = xlnx_mix_disp_crtc_atomic_get_property,
2455 .reset = drm_atomic_helper_crtc_reset,
2456 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
2457 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
2458 .enable_vblank = xlnx_mix_crtc_enable_vblank,
2459 .disable_vblank = xlnx_mix_crtc_disable_vblank,
2460};
2461
2462static void
2463xlnx_mix_crtc_atomic_enable(struct drm_crtc *crtc,
2464 struct drm_crtc_state *old_crtc_state)
2465{
2466 xlnx_mix_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
2467}
2468
2469
2470
2471
2472
2473
2474static void xlnx_mix_clear_event(struct drm_crtc *crtc)
2475{
2476 if (crtc->state->event) {
2477 complete_all(crtc->state->event->base.completion);
2478 crtc->state->event = NULL;
2479 }
2480}
2481
2482static void
2483xlnx_mix_crtc_atomic_disable(struct drm_crtc *crtc,
2484 struct drm_crtc_state *old_crtc_state)
2485{
2486 xlnx_mix_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
2487 xlnx_mix_clear_event(crtc);
2488}
2489
2490static void xlnx_mix_crtc_mode_set_nofb(struct drm_crtc *crtc)
2491{
2492}
2493
2494static int xlnx_mix_crtc_atomic_check(struct drm_crtc *crtc,
2495 struct drm_crtc_state *state)
2496{
2497 return drm_atomic_add_affected_planes(state->state, crtc);
2498}
2499
2500static void
2501xlnx_mix_crtc_atomic_begin(struct drm_crtc *crtc,
2502 struct drm_crtc_state *old_crtc_state)
2503{
2504
2505 if (crtc->state->event) {
2506 struct xlnx_crtc *xcrtc = to_xlnx_crtc(crtc);
2507 struct xlnx_mix *mixer = to_xlnx_mixer(xcrtc);
2508
2509
2510 crtc->state->event->pipe = drm_crtc_index(crtc);
2511 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
2512 mixer->event = crtc->state->event;
2513 crtc->state->event = NULL;
2514 }
2515}
2516
2517static struct drm_crtc_helper_funcs xlnx_mix_crtc_helper_funcs = {
2518 .atomic_enable = xlnx_mix_crtc_atomic_enable,
2519 .atomic_disable = xlnx_mix_crtc_atomic_disable,
2520 .mode_set_nofb = xlnx_mix_crtc_mode_set_nofb,
2521 .atomic_check = xlnx_mix_crtc_atomic_check,
2522 .atomic_begin = xlnx_mix_crtc_atomic_begin,
2523};
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533static int xlnx_mix_crtc_create(struct xlnx_mix *mixer)
2534{
2535 struct xlnx_crtc *crtc;
2536 struct drm_plane *primary_plane = NULL;
2537 struct drm_plane *cursor_plane = NULL;
2538 int ret, i;
2539
2540 crtc = &mixer->crtc;
2541 primary_plane = &mixer->drm_primary_layer->base;
2542 cursor_plane = &mixer->hw_logo_layer->base;
2543
2544 for (i = 0; i < mixer->num_planes; i++)
2545 xlnx_mix_attach_plane_prop(&mixer->planes[i]);
2546 mixer->pixel_clock = devm_clk_get(mixer->drm->dev, NULL);
2547 if (IS_ERR(mixer->pixel_clock)) {
2548 DRM_DEBUG_KMS("failed to get pixel clock\n");
2549 mixer->pixel_clock = NULL;
2550 }
2551 ret = clk_prepare_enable(mixer->pixel_clock);
2552 if (ret) {
2553 DRM_ERROR("failed to enable a pixel clock\n");
2554 mixer->pixel_clock_enabled = false;
2555 goto err_plane;
2556 }
2557 mixer->pixel_clock_enabled = true;
2558
2559 ret = drm_crtc_init_with_planes(mixer->drm, &crtc->crtc,
2560 &mixer->drm_primary_layer->base,
2561 &mixer->hw_logo_layer->base,
2562 &xlnx_mix_crtc_funcs, NULL);
2563 if (ret) {
2564 DRM_ERROR("failed to initialize mixer crtc\n");
2565 goto err_pixel_clk;
2566 }
2567 drm_crtc_helper_add(&crtc->crtc, &xlnx_mix_crtc_helper_funcs);
2568 crtc->get_max_width = &xlnx_mix_crtc_get_max_width;
2569 crtc->get_max_height = &xlnx_mix_crtc_get_max_height;
2570 crtc->get_align = &xlnx_mix_crtc_get_align;
2571 crtc->get_format = &xlnx_mix_crtc_get_format;
2572 crtc->get_cursor_height = &xlnx_mix_crtc_get_max_cursor_height;
2573 crtc->get_cursor_width = &xlnx_mix_crtc_get_max_cursor_width;
2574 xlnx_crtc_register(mixer->drm, crtc);
2575
2576 return 0;
2577
2578err_pixel_clk:
2579 if (mixer->pixel_clock_enabled) {
2580 clk_disable_unprepare(mixer->pixel_clock);
2581 mixer->pixel_clock_enabled = false;
2582 }
2583err_plane:
2584 return ret;
2585}
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598static void xlnx_mix_init(struct xlnx_mix_hw *mixer)
2599{
2600 u32 i;
2601 u32 bg_bpc = mixer->bg_layer_bpc;
2602 u64 rgb_bg_clr = (0xFFFF >> (XVMIX_MAX_BPC - bg_bpc)) << (bg_bpc * 2);
2603 enum xlnx_mix_layer_id layer_id;
2604 struct xlnx_mix_layer_data *layer_data;
2605
2606 layer_data = xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_MASTER);
2607 xlnx_mix_layer_disable(mixer, XVMIX_LAYER_ALL);
2608 xlnx_mix_set_active_area(mixer, layer_data->hw_config.max_width,
2609 layer_data->hw_config.max_height);
2610
2611 xlnx_mix_set_bkg_col(mixer, rgb_bg_clr);
2612
2613 for (i = 0; i < mixer->layer_cnt; i++) {
2614 layer_id = mixer->layer_data[i].id;
2615 layer_data = &mixer->layer_data[i];
2616 if (layer_id == XVMIX_LAYER_MASTER)
2617 continue;
2618 xlnx_mix_set_layer_window(mixer, layer_id, 0, 0,
2619 XVMIX_LAYER_WIDTH_MIN,
2620 XVMIX_LAYER_HEIGHT_MIN, 0);
2621 if (layer_data->hw_config.can_scale)
2622 xlnx_mix_set_layer_scaling(mixer, layer_id, 0);
2623 if (layer_data->hw_config.can_alpha)
2624 xlnx_mix_set_layer_alpha(mixer, layer_id,
2625 XVMIX_ALPHA_MAX);
2626 }
2627 xlnx_mix_intrpt_enable_done(mixer);
2628}
2629
2630static int xlnx_mix_bind(struct device *dev, struct device *master,
2631 void *data)
2632{
2633 struct xlnx_mix *mixer = dev_get_drvdata(dev);
2634 struct drm_device *drm = data;
2635 u32 ret;
2636
2637 mixer->drm = drm;
2638 ret = xlnx_mix_plane_create(dev, mixer);
2639 if (ret)
2640 return ret;
2641 ret = xlnx_mix_crtc_create(mixer);
2642 if (ret)
2643 return ret;
2644 xlnx_mix_init(&mixer->mixer_hw);
2645
2646 return ret;
2647}
2648
2649static void xlnx_mix_unbind(struct device *dev, struct device *master,
2650 void *data)
2651{
2652 struct xlnx_mix *mixer = dev_get_drvdata(dev);
2653
2654 dev_set_drvdata(dev, NULL);
2655 xlnx_mix_intrpt_disable(&mixer->mixer_hw);
2656 xlnx_crtc_unregister(mixer->drm, &mixer->crtc);
2657}
2658
2659static const struct component_ops xlnx_mix_component_ops = {
2660 .bind = xlnx_mix_bind,
2661 .unbind = xlnx_mix_unbind,
2662};
2663
2664static int xlnx_mix_probe(struct platform_device *pdev)
2665{
2666 struct xlnx_mix *mixer;
2667 int ret;
2668
2669 mixer = devm_kzalloc(&pdev->dev, sizeof(*mixer), GFP_KERNEL);
2670 if (!mixer)
2671 return -ENOMEM;
2672
2673
2674 platform_set_drvdata(pdev, mixer);
2675 ret = xlnx_mix_dt_parse(&pdev->dev, mixer);
2676 if (ret) {
2677 if (ret != -EPROBE_DEFER)
2678 dev_err(&pdev->dev, "Failed to probe mixer\n");
2679 return ret;
2680 }
2681
2682 ret = component_add(&pdev->dev, &xlnx_mix_component_ops);
2683 if (ret)
2684 goto err;
2685
2686 mixer->master = xlnx_drm_pipeline_init(pdev);
2687 if (IS_ERR(mixer->master)) {
2688 dev_err(&pdev->dev, "Failed to initialize the drm pipeline\n");
2689 goto err_component;
2690 }
2691
2692 dev_info(&pdev->dev, "Xilinx Mixer driver probed success\n");
2693 return ret;
2694
2695err_component:
2696 component_del(&pdev->dev, &xlnx_mix_component_ops);
2697err:
2698 return ret;
2699}
2700
2701static int xlnx_mix_remove(struct platform_device *pdev)
2702{
2703 struct xlnx_mix *mixer = platform_get_drvdata(pdev);
2704
2705 xlnx_drm_pipeline_exit(mixer->master);
2706 component_del(&pdev->dev, &xlnx_mix_component_ops);
2707 return 0;
2708}
2709
2710static const struct of_device_id xlnx_mix_of_match[] = {
2711 { .compatible = "xlnx,mixer-3.0", },
2712 { },
2713};
2714MODULE_DEVICE_TABLE(of, xlnx_mix_of_match);
2715
2716static struct platform_driver xlnx_mix_driver = {
2717 .probe = xlnx_mix_probe,
2718 .remove = xlnx_mix_remove,
2719 .driver = {
2720 .name = "xlnx-mixer",
2721 .of_match_table = xlnx_mix_of_match,
2722 },
2723};
2724
2725module_platform_driver(xlnx_mix_driver);
2726
2727MODULE_AUTHOR("Saurabh Sengar");
2728MODULE_DESCRIPTION("Xilinx Mixer Driver");
2729MODULE_LICENSE("GPL v2");
2730