1 // SPDX-License-Identifier: GPL-2.0
3 * Xilinx logicore video mixer driver
5 * Copyright (C) 2017 - 2018 Xilinx, Inc.
7 * Author: Saurabh Sengar <saurabhs@xilinx.com>
8 * : Jeffrey Mouroux <jmouroux@xilinx.com>
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>
24 #include <linux/of_dma.h>
25 #include <linux/of_address.h>
26 #include <linux/of_irq.h>
27 #include <linux/dmaengine.h>
29 #include "xlnx_crtc.h"
31 /**************************** Register Data **********************************/
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
73 /************************** Constant Definitions *****************************/
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
103 /*************************** STATIC DATA ************************************/
104 static const u32 color_table[] = {
107 DRM_FORMAT_XBGR2101010,
120 DRM_FORMAT_XVUY2101010,
127 /*********************** Inline Functions/Macros *****************************/
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)
134 * enum xlnx_mix_layer_id - Describes the layer by index to be acted upon
135 * @XVMIX_LAYER_MASTER: Master layer
136 * @XVMIX_LAYER_1: Layer 1
137 * @XVMIX_LAYER_2: Layer 2
138 * @XVMIX_LAYER_3: Layer 3
139 * @XVMIX_LAYER_4: Layer 4
140 * @XVMIX_LAYER_5: Layer 5
141 * @XVMIX_LAYER_6: Layer 6
142 * @XVMIX_LAYER_7: Layer 7
143 * @XVMIX_LAYER_8: Layer 8
144 * @XVMIX_LAYER_LOGO: Logo Layer
145 * @XVMIX_LAYER_ALL: Layer count
147 enum xlnx_mix_layer_id {
148 XVMIX_LAYER_MASTER = 0,
162 * struct xlnx_mix_layer_data - Describes the hardware configuration of a given
164 * @hw_config: struct specifying the IP hardware constraints for this layer
165 * @vid_fmt: DRM format for this layer
166 * @can_alpha: Indicates that layer alpha is enabled for this layer
167 * @can_scale: Indicates that layer scaling is enabled for this layer
168 * @is_streaming: Indicates layer is not using mixer DMA but streaming from
170 * @max_width: Max possible pixel width
171 * @max_height: Max possible pixel height
172 * @min_width: Min possible pixel width
173 * @min_height: Min possible pixel height
174 * @layer_regs: struct containing current cached register values
175 * @buff_addr: Current physical address of image buffer
176 * @x_pos: Current CRTC x offset
177 * @y_pos: Current CRTC y offset
178 * @width: Current width in pixels
179 * @height: Current hight in pixels
180 * @stride: Current stride (when Mixer is performing DMA)
181 * @alpha: Current alpha setting
182 * @is_active: Logical flag indicating layer in use. If false, calls to
183 * enable layer will be ignored.
184 * @scale_fact: Current scaling factor applied to layer
185 * @id: The logical layer id identifies which layer this struct describes
186 * (e.g. 0 = master, 1-7 = overlay).
188 * All mixer layers are reprsented by an instance of this struct:
189 * output streaming, overlay, logo.
190 * Current layer-specific register state is stored in the layer_regs struct.
191 * The hardware configuration is stored in struct hw_config.
194 * Some properties of the logo layer are unique and not described in this
195 * struct. Those properites are part of the xlnx_mix struct as global
198 struct xlnx_mix_layer_data {
223 enum xlnx_mix_layer_id id;
227 * struct xlnx_mix_hw - Describes a mixer IP block instance within the design
228 * @base: Base physical address of Mixer IP in memory map
229 * @logo_layer_en: Indicates logo layer is enabled in hardware
230 * @logo_pixel_alpha_enabled: Indicates that per-pixel alpha supported for logo
232 * @max_layer_width: Max possible width for any layer on this Mixer
233 * @max_layer_height: Max possible height for any layer on this Mixer
234 * @max_logo_layer_width: Min possible width for any layer on this Mixer
235 * @max_logo_layer_height: Min possible height for any layer on this Mixer
236 * @max_layers: Max number of layers (excl: logo)
237 * @bg_layer_bpc: Bits per component for the background streaming layer
238 * @dma_addr_size: dma address size in bits
239 * @ppc: Pixels per component
240 * @irq: Interrupt request number assigned
241 * @bg_color: Current RGB color value for internal background color generator
242 * @layer_data: Array of layer data
243 * @layer_cnt: Layer data array count
244 * @reset_gpio: GPIO line used to reset IP between modesetting operations
245 * @intrpt_handler_fn: Interrupt handler function called when frame is completed
246 * @intrpt_data: Data pointer passed to interrupt handler
248 * Used as the primary data structure for many L2 driver functions. Logo layer
249 * data, if enabled within the IP, is described in this structure. All other
250 * layers are described by an instance of xlnx_mix_layer_data referenced by this
257 bool logo_pixel_alpha_enabled;
259 u32 max_layer_height;
260 u32 max_logo_layer_width;
261 u32 max_logo_layer_height;
268 struct xlnx_mix_layer_data *layer_data;
270 struct gpio_desc *reset_gpio;
271 void (*intrpt_handler_fn)(void *);
276 * struct xlnx_mix - Container for interfacing DRM driver to mixer
277 * @mixer_hw: Object representing actual hardware state of mixer
278 * @master: Logical master device from xlnx drm
279 * @crtc: Xilinx DRM driver crtc object
280 * @drm_primary_layer: Hardware layer serving as logical DRM primary layer
281 * @hw_master_layer: Base video streaming layer
282 * @hw_logo_layer: Hardware logo layer
283 * @planes: Mixer overlay layers
284 * @num_planes : number of planes
285 * @max_width : maximum width of plane
286 * @max_height : maximum height of plane
287 * @max_cursor_width : maximum cursor width
288 * @max_cursor_height: maximum cursor height
289 * @alpha_prop: Global layer alpha property
290 * @scale_prop: Layer scale property (1x, 2x or 4x)
291 * @bg_color: Background color property for primary layer
292 * @drm: core drm object
293 * @pixel_clock: pixel clock for mixer
294 * @pixel_clock_enabled: pixel clock status
295 * @dpms: mixer drm state
296 * @event: vblank pending event
298 * Contains pointers to logical constructions such as the DRM plane manager as
299 * well as pointers to distinquish the mixer layer serving as the DRM "primary"
300 * plane from the actual mixer layer which serves as the background layer in
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;
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;
324 struct drm_pending_vblank_event *event;
328 * struct xlnx_mix_plane_dma - Xilinx drm plane VDMA object
331 * @xt: dma interleaved configuration template
332 * @sgl: data chunk for dma_interleaved_template
333 * @is_active: flag if the DMA is active
335 struct xlnx_mix_plane_dma {
336 struct dma_chan *chan;
337 struct dma_interleaved_template xt;
338 struct data_chunk sgl[1];
343 * struct xlnx_mix_plane - Xilinx drm plane object
345 * @base: base drm plane object
346 * @mixer_layer: video mixer hardware layer data instance
347 * @mixer: mixer DRM object
350 * @dpms: current dpms level
351 * @format: pixel format
353 struct 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];
363 static inline void reg_writel(void __iomem *base, int offset, u32 val)
365 writel(val, base + offset);
368 static inline void reg_writeq(void __iomem *base, int offset, u64 val)
370 writel(upper_32_bits(val), base + offset);
371 writel(lower_32_bits(val), base + offset + 4);
374 static inline u32 reg_readl(void __iomem *base, int offset)
376 return readl(base + offset);
380 * xlnx_mix_intrpt_enable_done - Enables interrupts
381 * @mixer: instance of mixer IP core
383 * Enables interrupts in the mixer core
385 static void xlnx_mix_intrpt_enable_done(struct xlnx_mix_hw *mixer)
387 u32 curr_val = reg_readl(mixer->base, XVMIX_IER);
389 /* Enable Interrupts */
390 reg_writel(mixer->base, XVMIX_IER, curr_val | XVMIX_IRQ_DONE_MASK);
391 reg_writel(mixer->base, XVMIX_GIE, XVMIX_GIE_EN_MASK);
395 * xlnx_mix_intrpt_disable - Disable interrupts
396 * @mixer: instance of mixer IP core
398 * Disables interrupts in the mixer core
400 static void xlnx_mix_intrpt_disable(struct xlnx_mix_hw *mixer)
402 u32 curr_val = reg_readl(mixer->base, XVMIX_IER);
404 reg_writel(mixer->base, XVMIX_IER, curr_val & (~XVMIX_IRQ_DONE_MASK));
405 reg_writel(mixer->base, XVMIX_GIE, 0);
409 * xlnx_mix_start - Start the mixer core video generator
410 * @mixer: Mixer core instance for which to start video output
412 * Starts the core to generate a video frame.
414 static void xlnx_mix_start(struct xlnx_mix_hw *mixer)
418 val = XVMIX_AP_RST_MASK | XVMIX_AP_EN_MASK;
419 reg_writel(mixer->base, XVMIX_AP_CTRL, val);
423 * xlnx_mix_stop - Stop the mixer core video generator
424 * @mixer: Mixer core instance for which to stop video output
426 * Starts the core to generate a video frame.
428 static void xlnx_mix_stop(struct xlnx_mix_hw *mixer)
430 reg_writel(mixer->base, XVMIX_AP_CTRL, 0);
433 static inline uint32_t xlnx_mix_get_intr_status(struct xlnx_mix_hw *mixer)
435 return reg_readl(mixer->base, XVMIX_ISR) & XVMIX_IRQ_DONE_MASK;
438 static inline void xlnx_mix_clear_intr_status(struct xlnx_mix_hw *mixer,
441 reg_writel(mixer->base, XVMIX_ISR, intr);
445 * xlnx_mix_get_layer_data - Retrieve current hardware and register
446 * values for a logical video layer
447 * @mixer: Mixer instance to interrogate
448 * @id: Id of layer for which data is requested
451 * Structure containing layer-specific data; NULL upon failure
453 static struct xlnx_mix_layer_data *
454 xlnx_mix_get_layer_data(struct xlnx_mix_hw *mixer, enum xlnx_mix_layer_id id)
457 struct xlnx_mix_layer_data *layer_data;
459 for (i = 0; i <= (mixer->layer_cnt - 1); i++) {
460 layer_data = &mixer->layer_data[i];
461 if (layer_data->id == id)
468 * xlnx_mix_set_active_area - Sets the number of active horizontal and
469 * vertical scan lines for the mixer background layer.
470 * @mixer: Mixer instance for which to set a new viewable area
471 * @hactive: Width of new background image dimension
472 * @vactive: Height of new background image dimension
474 * Minimum values are 64x64 with maximum values determined by the IP hardware
478 * Zero on success, -EINVAL on failure
480 static int xlnx_mix_set_active_area(struct xlnx_mix_hw *mixer,
481 u32 hactive, u32 vactive)
483 struct xlnx_mix_layer_data *ld =
484 xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_MASTER);
486 if (hactive > ld->hw_config.max_width ||
487 vactive > ld->hw_config.max_height) {
488 DRM_ERROR("Invalid layer dimention\n");
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;
501 * is_window_valid - Validate requested plane dimensions
502 * @mixer: Mixer core instance for which to stop video output
503 * @x_pos: x position requested for start of plane
504 * @y_pos: y position requested for start of plane
505 * @width: width of plane
506 * @height: height of plane
507 * @scale: scale factor of plane
509 * Validates if the requested window is within the frame boundary
512 * true on success, false on failure
514 static bool is_window_valid(struct xlnx_mix_hw *mixer, u32 x_pos, u32 y_pos,
515 u32 width, u32 height, u32 scale)
517 struct xlnx_mix_layer_data *master_layer;
518 int scale_factor[3] = {1, 2, 4};
520 master_layer = xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_MASTER);
522 /* Check if window scale factor is set */
523 if (scale < XVMIX_SCALE_FACTOR_INVALID) {
524 width *= scale_factor[scale];
525 height *= scale_factor[scale];
528 /* verify overlay falls within currently active background area */
529 if (((x_pos + width) <= master_layer->layer_regs.width) &&
530 ((y_pos + height) <= master_layer->layer_regs.height))
533 DRM_ERROR("Requested plane dimensions can't be set\n");
538 * xlnx_mix_layer_enable - Enables the requested layers
539 * @mixer: Mixer instance in which to enable a video layer
540 * @id: Logical id (e.g. 8 = logo layer) to enable
542 * Enables (permit video output) for layers in mixer
543 * Enables the layer denoted by id in the IP core.
544 * Layer 0 will indicate the background layer and layer 8 the logo
545 * layer. Passing in the enum value XVMIX_LAYER_ALL will enable all
547 static void xlnx_mix_layer_enable(struct xlnx_mix_hw *mixer,
548 enum xlnx_mix_layer_id id)
550 struct xlnx_mix_layer_data *layer_data;
553 /* Ensure layer is marked as 'active' by application before
554 * turning on in hardware. In some cases, layer register data
555 * may be written to otherwise inactive layers in lieu of, eventually,
558 layer_data = xlnx_mix_get_layer_data(mixer, id);
560 DRM_ERROR("Invalid layer id %d\n", id);
563 if (!layer_data->layer_regs.is_active)
564 return; /* for inactive layers silently return */
566 /* Check if request is to enable all layers or single layer */
567 if (id == XVMIX_LAYER_ALL) {
568 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA,
569 XVMIX_MASK_ENABLE_ALL_LAYERS);
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;
577 curr_state |= BIT(id);
578 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA, curr_state);
580 DRM_ERROR("Can't enable requested layer %d\n", id);
585 * xlnx_mix_disp_layer_enable - Enables video output represented by the
587 * @plane: Drm plane object describing video layer to enable
590 static void xlnx_mix_disp_layer_enable(struct xlnx_mix_plane *plane)
592 struct xlnx_mix_hw *mixer_hw;
593 struct xlnx_mix_layer_data *l_data;
598 mixer_hw = to_mixer_hw(plane);
599 l_data = plane->mixer_layer;
601 if (id < XVMIX_LAYER_MASTER || id > XVMIX_LAYER_LOGO) {
602 DRM_DEBUG_KMS("Attempt to activate invalid layer: %d\n", id);
605 if (id == XVMIX_LAYER_MASTER && !l_data->hw_config.is_streaming)
608 xlnx_mix_layer_enable(mixer_hw, id);
612 * xlnx_mix_layer_disable - Disables the requested layer
613 * @mixer: Mixer for which the layer will be disabled
614 * @id: Logical id of the layer to be disabled (0-8)
616 * Disables the layer denoted by layer_id in the IP core.
617 * Layer 0 will indicate the background layer and layer 8 the logo
618 * layer. Passing in the enum value XVMIX_LAYER_ALL will disable all
621 static void xlnx_mix_layer_disable(struct xlnx_mix_hw *mixer,
622 enum xlnx_mix_layer_id id)
624 u32 num_layers, curr_state;
626 num_layers = mixer->layer_cnt;
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;
637 curr_state &= ~(BIT(id));
638 reg_writel(mixer->base, XVMIX_LAYERENABLE_DATA, curr_state);
640 DRM_ERROR("Can't disable requested layer %d\n", id);
645 * xlnx_mix_disp_layer_disable - Disables video output represented by the
647 * @plane: Drm plane object describing video layer to disable
650 static void xlnx_mix_disp_layer_disable(struct xlnx_mix_plane *plane)
652 struct xlnx_mix_hw *mixer_hw;
656 mixer_hw = to_mixer_hw(plane);
659 layer_id = plane->mixer_layer->id;
660 if (layer_id < XVMIX_LAYER_MASTER || layer_id > XVMIX_LAYER_LOGO)
663 xlnx_mix_layer_disable(mixer_hw, layer_id);
666 static int xlnx_mix_mark_layer_inactive(struct xlnx_mix_plane *plane)
668 if (!plane || !plane->mixer_layer)
671 plane->mixer_layer->layer_regs.is_active = false;
676 /* apply mode to plane pipe */
677 static void xlnx_mix_plane_commit(struct drm_plane *base_plane)
679 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
680 struct dma_async_tx_descriptor *desc;
681 enum dma_ctrl_flags flags;
684 /* for xlnx video framebuffer dma, if used */
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];
689 if (dma->chan && dma->is_active) {
690 flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
691 desc = dmaengine_prep_interleaved_dma(dma->chan,
695 DRM_ERROR("failed to prepare DMA descriptor\n");
698 dmaengine_submit(desc);
699 dma_async_issue_pending(dma->chan);
704 static int xlnx_mix_plane_get_max_width(struct drm_plane *base_plane)
706 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
708 return plane->mixer->max_width;
711 static int xlnx_mix_plane_get_max_height(struct drm_plane *base_plane)
713 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
715 return plane->mixer->max_height;
718 static int xlnx_mix_plane_get_max_cursor_width(struct drm_plane *base_plane)
720 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
722 return plane->mixer->max_cursor_width;
725 static int xlnx_mix_plane_get_max_cursor_height(struct drm_plane *base_plane)
727 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
729 return plane->mixer->max_cursor_height;
732 static int xlnx_mix_crtc_get_max_width(struct xlnx_crtc *crtc)
734 return xlnx_mix_plane_get_max_width(crtc->crtc.primary);
737 static int xlnx_mix_crtc_get_max_height(struct xlnx_crtc *crtc)
739 return xlnx_mix_plane_get_max_height(crtc->crtc.primary);
742 static unsigned int xlnx_mix_crtc_get_max_cursor_width(struct xlnx_crtc *crtc)
744 return xlnx_mix_plane_get_max_cursor_width(crtc->crtc.primary);
747 static unsigned int xlnx_mix_crtc_get_max_cursor_height(struct xlnx_crtc *crtc)
749 return xlnx_mix_plane_get_max_cursor_height(crtc->crtc.primary);
753 * xlnx_mix_crtc_get_format - Get the current device format
754 * @crtc: xlnx crtc object
756 * Get the current format of pipeline
758 * Return: the corresponding DRM_FORMAT_XXX
760 static uint32_t xlnx_mix_crtc_get_format(struct xlnx_crtc *crtc)
762 struct xlnx_mix_plane *plane = to_xlnx_plane(crtc->crtc.primary);
764 return plane->format;
768 * xlnx_mix_crtc_get_align - Get the alignment value for pitch
769 * @crtc: xlnx crtc object
771 * Get the alignment value for pitch from the plane
773 * Return: The alignment value if successful, or the error code.
775 static unsigned int xlnx_mix_crtc_get_align(struct xlnx_crtc *crtc)
777 struct xlnx_mix_plane *plane = to_xlnx_plane(crtc->crtc.primary);
778 struct xlnx_mix *m = plane->mixer;
780 return XVMIX_BASE_ALIGN * m->mixer_hw.ppc;
784 * xlnx_mix_attach_plane_prop - Attach mixer-specific drm property to
786 * @plane: Xilinx drm plane object to inspect and attach appropriate
789 * The linked mixer layer will be inspected to see what capabilities it offers
790 * (e.g. global layer alpha; scaling) and drm property objects that indicate
791 * those capabilities will then be attached and initialized to default values.
793 static void xlnx_mix_attach_plane_prop(struct xlnx_mix_plane *plane)
795 struct drm_mode_object *base = &plane->base.base;
796 struct xlnx_mix *mixer = plane->mixer;
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,
806 static int xlnx_mix_mark_layer_active(struct xlnx_mix_plane *plane)
808 if (!plane->mixer_layer)
810 plane->mixer_layer->layer_regs.is_active = true;
815 static bool xlnx_mix_isfmt_support(u32 format)
819 for (i = 0; i < ARRAY_SIZE(color_table); i++) {
820 if (format == color_table[i])
826 /*************** DISPLAY ************/
829 * xlnx_mix_get_layer_scaling - Get layer scaling factor
830 * @mixer: Mixer instance to program with new background color
833 * Applicable only for overlay layers
836 * scaling factor of the specified layer
838 static int xlnx_mix_get_layer_scaling(struct xlnx_mix_hw *mixer,
839 enum xlnx_mix_layer_id id)
841 int scale_factor = 0;
843 struct xlnx_mix_layer_data *l_data = xlnx_mix_get_layer_data(mixer, 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;
854 default: /*Layer0-Layer7*/
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;
866 * xlnx_mix_set_layer_window - Sets the position of an overlay layer
867 * @mixer: Specific mixer object instance controlling the video
868 * @id: Logical layer id (1-7) to be positioned
869 * @x_pos: new: Column to start display of overlay layer
870 * @y_pos: new: Row to start display of overlay layer
871 * @width: Number of active columns to dislay for overlay layer
872 * @height: Number of active columns to display for overlay layer
873 * @stride: Width in bytes of overaly memory buffer (memory layer only)
875 * Sets the position of an overlay layer over the background layer (layer 0)
876 * Applicable only for layers 1-7 or the logo layer
879 * Zero on success, -EINVAL if position is invalid or -ENODEV if layer
881 static 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,
886 struct xlnx_mix_layer_data *l_data;
888 int status = -EINVAL;
889 u32 x_reg, y_reg, w_reg, h_reg, s_reg;
892 l_data = xlnx_mix_get_layer_data(mixer, id);
896 scale = xlnx_mix_get_layer_scaling(mixer, id);
897 if (!is_window_valid(mixer, x_pos, y_pos, width, height, scale))
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))
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;
924 default: /*Layer1-Layer7*/
926 if (!(id < mixer->layer_cnt &&
927 width <= l_data->hw_config.max_width &&
928 width >= l_data->hw_config.min_width))
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;
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;
946 if (!l_data->hw_config.is_streaming)
947 reg_writel(mixer->base, (s_reg + off), stride);
955 * xlnx_mix_set_layer_dimensions - Set layer dimensions
956 * @plane: Drm plane object desribing video layer to reposition
957 * @crtc_x: New horizontal anchor postion from which to begin rendering
958 * @crtc_y: New vertical anchor position from which to begin rendering
959 * @width: Width, in pixels, to render from stream or memory buffer
960 * @height: Height, in pixels, to render from stream or memory buffer
961 * @stride: Width, in bytes, of a memory buffer. Used only for
962 * memory layers. Use 0 for streaming layers.
964 * Establishes new coordinates and dimensions for a video plane layer
965 * New size and coordinates of window must fit within the currently active
966 * area of the crtc (e.g. the background resolution)
968 * Return: 0 if successful; Either -EINVAL if coordindate data is invalid
969 * or -ENODEV if layer data not present
971 static 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)
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;
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);
988 xlnx_mix_layer_disable(mixer_hw, layer_id);
990 if (mixer->drm_primary_layer == plane) {
993 ret = xlnx_mix_set_active_area(mixer_hw, width, height);
996 xlnx_mix_layer_enable(mixer_hw, XVMIX_LAYER_MASTER);
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);
1003 xlnx_mix_disp_layer_enable(plane);
1009 * xlnx_mix_set_layer_scaling - Sets scaling factor
1010 * @mixer: Instance of mixer to be subject of scaling request
1011 * @id: Logical id of video layer subject to new scale setting
1012 * @scale: scale Factor (1x, 2x or 4x) for horiz. and vert. dimensions
1014 * Sets the scaling factor for the specified video layer
1015 * Not applicable to background stream layer (layer 0)
1018 * Zero on success, -EINVAL on failure to set scale for layer (likely
1019 * returned if resulting size of layer exceeds dimensions of active
1022 static int xlnx_mix_set_layer_scaling(struct xlnx_mix_hw *mixer,
1023 enum xlnx_mix_layer_id id, u32 scale)
1025 void __iomem *reg = mixer->base;
1026 struct xlnx_mix_layer_data *l_data;
1028 u32 x_pos, y_pos, width, height, offset;
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;
1036 if (!is_window_valid(mixer, x_pos, y_pos, width, height, scale))
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;
1048 default: /* Layer0-Layer7 */
1049 if (id < mixer->layer_cnt && l_data->hw_config.can_scale) {
1050 offset = id * XVMIX_REG_OFFSET;
1052 reg_writel(reg, (XVMIX_LAYERSCALE_0_DATA + offset),
1054 l_data->layer_regs.scale_fact = scale;
1063 * xlnx_mix_set_layer_scale - Change video scale factor for video plane
1064 * @plane: Drm plane object describing layer to be modified
1065 * @val: Index of scale factor to use:
1071 * Zero on success, either -EINVAL if scale value is illegal or
1072 * -ENODEV if layer does not exist (null)
1074 static int xlnx_mix_set_layer_scale(struct xlnx_mix_plane *plane,
1077 struct xlnx_mix_hw *mixer_hw = to_mixer_hw(plane);
1078 struct xlnx_mix_layer_data *layer = plane->mixer_layer;
1081 if (!layer || !layer->hw_config.can_scale)
1083 if (val > XVMIX_SCALE_FACTOR_4X || val < XVMIX_SCALE_FACTOR_1X) {
1084 DRM_ERROR("Mixer layer scale value illegal.\n");
1087 xlnx_mix_disp_layer_disable(plane);
1089 ret = xlnx_mix_set_layer_scaling(mixer_hw, layer->id, val);
1090 xlnx_mix_disp_layer_enable(plane);
1096 * xlnx_mix_set_layer_alpha - Set the alpha value
1097 * @mixer: Instance of mixer controlling layer to modify
1098 * @layer_id: Logical id of video overlay to adjust alpha setting
1099 * @alpha: Desired alpha setting (0-255) for layer specified
1100 * 255 = completely opaque
1101 * 0 = fully transparent
1103 * Set the layer global transparency for a video overlay
1104 * Not applicable to background streaming layer
1107 * Zero on success, -EINVAL on failure
1109 static int xlnx_mix_set_layer_alpha(struct xlnx_mix_hw *mixer,
1110 enum xlnx_mix_layer_id layer_id, u32 alpha)
1112 struct xlnx_mix_layer_data *layer_data;
1114 int status = -EINVAL;
1116 layer_data = xlnx_mix_get_layer_data(mixer, 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;
1127 default: /*Layer1-Layer7*/
1128 if (layer_id < mixer->layer_cnt &&
1129 layer_data->hw_config.can_alpha) {
1130 u32 offset = layer_id * XVMIX_REG_OFFSET;
1132 reg = XVMIX_LAYERALPHA_0_DATA;
1133 reg_writel(mixer->base, (reg + offset), alpha);
1134 layer_data->layer_regs.alpha = alpha;
1143 * xlnx_mix_disp_set_layer_alpha - Change the transparency of an entire plane
1144 * @plane: Video layer affected by new alpha setting
1145 * @val: Value of transparency setting (0-255) with 255 being opaque
1146 * 0 being fully transparent
1149 * Zero on success, -EINVAL on failure
1151 static int xlnx_mix_disp_set_layer_alpha(struct xlnx_mix_plane *plane,
1154 struct xlnx_mix_hw *mixer_hw = to_mixer_hw(plane);
1155 struct xlnx_mix_layer_data *layer = plane->mixer_layer;
1157 if (!layer || !layer->hw_config.can_alpha)
1159 if (val > XVMIX_ALPHA_MAX || val < XVMIX_ALPHA_MIN) {
1160 DRM_ERROR("Mixer layer alpha dts value illegal.\n");
1163 return xlnx_mix_set_layer_alpha(mixer_hw, layer->id, val);
1167 * xlnx_mix_set_layer_buff_addr - Set buff addr for layer
1168 * @mixer: Instance of mixer controlling layer to modify
1169 * @id: Logical id of video overlay to adjust alpha setting
1170 * @luma_addr: Start address of plane 1 of frame buffer for layer 1
1171 * @chroma_addr: Start address of plane 2 of frame buffer for layer 1
1173 * Sets the buffer address of the specified layer
1175 * Zero on success, -EINVAL on failure
1177 static 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)
1181 struct xlnx_mix_layer_data *layer_data;
1185 if (id >= mixer->layer_cnt)
1188 /* Check if addr is aligned to aximm width (PPC * 64-bits) */
1189 align = mixer->ppc * 8;
1190 if ((luma_addr % align) != 0 || (chroma_addr % align) != 0)
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);
1201 reg_writel(mixer->base, reg1, (u32)luma_addr);
1202 reg_writel(mixer->base, reg2, (u32)chroma_addr);
1204 layer_data->layer_regs.buff_addr1 = luma_addr;
1205 layer_data->layer_regs.buff_addr2 = chroma_addr;
1211 * xlnx_mix_hw_plane_dpms - Implementation of display power management
1212 * system call (dpms).
1213 * @plane: Plane/mixer layer to enable/disable (based on dpms value)
1214 * @dpms: Display power management state to act upon
1216 * Designed to disable and turn off a plane and restore all attached drm
1217 * properities to their initial values. Alterntively, if dpms is "on", will
1222 xlnx_mix_hw_plane_dpms(struct xlnx_mix_plane *plane, int dpms)
1224 struct xlnx_mix *mixer;
1228 mixer = plane->mixer;
1232 case DRM_MODE_DPMS_ON:
1233 xlnx_mix_disp_layer_enable(plane);
1236 xlnx_mix_mark_layer_inactive(plane);
1237 xlnx_mix_disp_layer_disable(plane);
1238 /* restore to default property values */
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);
1246 static void xlnx_mix_plane_dpms(struct drm_plane *base_plane, int dpms)
1248 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1251 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
1252 DRM_DEBUG_KMS("dpms: %d -> %d\n", plane->dpms, dpms);
1254 if (plane->dpms == dpms)
1258 case DRM_MODE_DPMS_ON:
1259 /* start dma engine */
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);
1266 xlnx_mix_hw_plane_dpms(plane, dpms);
1267 /* stop dma engine and release descriptors */
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;
1279 xlnx_mix_disp_plane_atomic_set_property(struct drm_plane *base_plane,
1280 struct drm_plane_state *state,
1281 struct drm_property *property, u64 val)
1283 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1284 struct xlnx_mix *mixer = plane->mixer;
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);
1296 xlnx_mix_disp_plane_atomic_get_property(struct drm_plane *base_plane,
1297 const struct drm_plane_state *state,
1298 struct drm_property *property,
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;
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;
1316 static struct drm_plane_funcs xlnx_mix_plane_funcs = {
1317 .update_plane = drm_atomic_helper_update_plane,
1318 .disable_plane = drm_atomic_helper_disable_plane,
1319 .atomic_set_property = xlnx_mix_disp_plane_atomic_set_property,
1320 .atomic_get_property = xlnx_mix_disp_plane_atomic_get_property,
1321 .destroy = drm_plane_cleanup,
1322 .reset = drm_atomic_helper_plane_reset,
1323 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
1324 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
1328 * xlnx_mix_logo_load - Loads mixer's internal bram
1329 * @mixer: Mixer instance to act upon
1330 * @logo_w: Width of logo in pixels
1331 * @logo_h: Height of logo in pixels
1332 * @r_buf: Pointer to byte buffer array of R data values
1333 * @g_buf: Pointer to byte buffer array of G data values
1334 * @b_buf: Pointer to byte buffer array of B data values
1335 * @a_buf: Pointer to byte buffer array of A data values
1337 * Loads mixer's internal bram with planar R, G, B and A data
1340 * Zero on success, -ENODEV if logo layer not enabled; -EINVAL otherwise
1342 static int xlnx_mix_logo_load(struct xlnx_mix_hw *mixer, u32 logo_w, u32 logo_h,
1343 u8 *r_buf, u8 *g_buf, u8 *b_buf, u8 *a_buf)
1345 void __iomem *reg = mixer->base;
1346 struct xlnx_mix_layer_data *layer_data;
1350 u32 rword, gword, bword, aword;
1351 u32 pixel_cnt = logo_w * logo_h;
1352 u32 unaligned_pix_cnt = pixel_cnt % 4;
1353 u32 width, height, curr_x_pos, curr_y_pos;
1354 u32 rbase_addr, gbase_addr, bbase_addr, abase_addr;
1356 layer_data = xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_LOGO);
1365 /* RGBA data should be 32-bit word aligned */
1366 if (unaligned_pix_cnt && mixer->logo_pixel_alpha_enabled)
1369 if (!(mixer->logo_layer_en &&
1370 logo_w <= layer_data->hw_config.max_width &&
1371 logo_h <= layer_data->hw_config.max_height))
1376 rbase_addr = XVMIX_LOGOR_V_BASE;
1377 gbase_addr = XVMIX_LOGOG_V_BASE;
1378 bbase_addr = XVMIX_LOGOB_V_BASE;
1379 abase_addr = XVMIX_LOGOA_V_BASE;
1381 for (x = 0; x < pixel_cnt; x++) {
1382 shift = (x % 4) * 8;
1383 rword |= r_buf[x] << shift;
1384 gword |= g_buf[x] << shift;
1385 bword |= b_buf[x] << shift;
1386 if (mixer->logo_pixel_alpha_enabled)
1387 aword |= a_buf[x] << shift;
1390 reg_writel(reg, (rbase_addr + (x - 3)), rword);
1391 reg_writel(reg, (gbase_addr + (x - 3)), gword);
1392 reg_writel(reg, (bbase_addr + (x - 3)), bword);
1393 if (mixer->logo_pixel_alpha_enabled)
1394 reg_writel(reg, (abase_addr + (x - 3)), aword);
1398 curr_x_pos = layer_data->layer_regs.x_pos;
1399 curr_y_pos = layer_data->layer_regs.y_pos;
1400 return xlnx_mix_set_layer_window(mixer, XVMIX_LAYER_LOGO, curr_x_pos,
1401 curr_y_pos, logo_w, logo_h, 0);
1404 static int xlnx_mix_update_logo_img(struct xlnx_mix_plane *plane,
1405 struct drm_gem_cma_object *buffer,
1406 u32 src_w, u32 src_h)
1408 struct xlnx_mix_layer_data *logo_layer = plane->mixer_layer;
1409 size_t pixel_cnt = src_h * src_w;
1410 /* color comp defaults to offset in RG24 buffer */
1413 bool per_pixel_alpha = false;
1414 u32 max_width = logo_layer->hw_config.max_width;
1415 u32 max_height = logo_layer->hw_config.max_height;
1416 u32 min_width = logo_layer->hw_config.min_width;
1417 u32 min_height = logo_layer->hw_config.min_height;
1422 size_t el_size = sizeof(u8);
1426 /* ensure valid conditions for update */
1427 if (logo_layer->id != XVMIX_LAYER_LOGO)
1430 if (src_h > max_height || src_w > max_width ||
1431 src_h < min_height || src_w < min_width) {
1432 DRM_ERROR("Mixer logo/cursor layer dimensions illegal.\n");
1436 if (!xlnx_mix_isfmt_support(plane->mixer_layer->hw_config.vid_fmt)) {
1437 DRM_ERROR("DRM color format not supported for logo layer\n");
1440 per_pixel_alpha = (logo_layer->hw_config.vid_fmt ==
1441 DRM_FORMAT_RGBA8888) ? true : false;
1442 r_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1443 g_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1444 b_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1445 if (per_pixel_alpha)
1446 a_data = kcalloc(pixel_cnt, el_size, GFP_KERNEL);
1448 if (!r_data || !g_data || !b_data || (per_pixel_alpha && !a_data)) {
1449 DRM_ERROR("Unable to allocate memory for logo layer data\n");
1453 pix_cmp_cnt = per_pixel_alpha ? 4 : 3;
1454 logo_cmp_cnt = pixel_cnt * pix_cmp_cnt;
1455 /* ensure buffer attributes have changed to indicate new logo
1458 if ((phys_addr_t)buffer->vaddr == logo_layer->layer_regs.buff_addr1 &&
1459 src_w == logo_layer->layer_regs.width &&
1460 src_h == logo_layer->layer_regs.height)
1463 /* cache buffer address for future comparison */
1464 logo_layer->layer_regs.buff_addr1 = (phys_addr_t)buffer->vaddr;
1465 pixel_mem_data = (u8 *)(buffer->vaddr);
1466 for (i = 0, j = 0; j < pixel_cnt; j++) {
1467 if (per_pixel_alpha && a_data)
1468 a_data[j] = pixel_mem_data[i++];
1470 b_data[j] = pixel_mem_data[i++];
1471 g_data[j] = pixel_mem_data[i++];
1472 r_data[j] = pixel_mem_data[i++];
1474 ret = xlnx_mix_logo_load(to_mixer_hw(plane), src_w, src_h, r_data,
1476 per_pixel_alpha ? a_data : NULL);
1487 * xlnx_mix_set_plane - Implementation of DRM plane_update callback
1488 * @plane: xlnx_mix_plane object containing references to
1489 * the base plane and mixer
1490 * @fb: Framebuffer descriptor
1491 * @crtc_x: X position of layer on crtc. Note, if the plane represents either
1492 * the master hardware layer (video0) or the layer representing the DRM primary
1493 * layer, the crtc x/y coordinates are either ignored and/or set to 0/0
1495 * @crtc_y: Y position of layer. See description of crtc_x handling
1496 * for more inforation.
1497 * @src_x: x-offset in memory buffer from which to start reading
1498 * @src_y: y-offset in memory buffer from which to start reading
1499 * @src_w: Number of horizontal pixels to read from memory per row
1500 * @src_h: Number of rows of video data to read from memory
1502 * Configures a mixer layer to comply with user space SET_PLANE icotl
1506 * Zero on success, non-zero linux error code otherwise.
1508 static int xlnx_mix_set_plane(struct xlnx_mix_plane *plane,
1509 struct drm_framebuffer *fb,
1510 int crtc_x, int crtc_y,
1511 u32 src_x, u32 src_y,
1512 u32 src_w, u32 src_h)
1514 struct xlnx_mix_hw *mixer_hw;
1515 struct xlnx_mix *mixer;
1516 struct drm_gem_cma_object *luma_buffer;
1517 u32 luma_stride = fb->pitches[0];
1518 u64 luma_addr, chroma_addr = 0;
1519 u32 active_area_width;
1520 u32 active_area_height;
1521 enum xlnx_mix_layer_id layer_id;
1523 const struct drm_format_info *info = fb->format;
1525 mixer = plane->mixer;
1526 mixer_hw = &mixer->mixer_hw;
1527 layer_id = plane->mixer_layer->id;
1529 mixer->drm_primary_layer->mixer_layer->layer_regs.width;
1530 active_area_height =
1531 mixer->drm_primary_layer->mixer_layer->layer_regs.height;
1532 /* compute memory data */
1533 luma_buffer = drm_fb_cma_get_gem_obj(fb, 0);
1534 luma_addr = drm_fb_cma_get_gem_addr(fb, plane->base.state, 0);
1536 DRM_ERROR("%s failed to get luma paddr\n", __func__);
1540 if (info->num_planes > 1) {
1541 chroma_addr = drm_fb_cma_get_gem_addr(fb, plane->base.state, 1);
1543 DRM_ERROR("failed to get chroma paddr\n");
1547 ret = xlnx_mix_mark_layer_active(plane);
1552 case XVMIX_LAYER_LOGO:
1553 ret = xlnx_mix_update_logo_img(plane, luma_buffer,
1558 ret = xlnx_mix_set_layer_dimensions(plane, crtc_x, crtc_y,
1559 src_w, src_h, luma_stride);
1562 case XVMIX_LAYER_MASTER:
1563 if (!plane->mixer_layer->hw_config.is_streaming)
1564 xlnx_mix_mark_layer_inactive(plane);
1565 if (mixer->drm_primary_layer == mixer->hw_master_layer) {
1566 xlnx_mix_layer_disable(mixer_hw, layer_id);
1568 ret = xlnx_mix_set_active_area(mixer_hw, src_w, src_h);
1571 xlnx_mix_layer_enable(mixer_hw, layer_id);
1573 } else if (src_w != active_area_width ||
1574 src_h != active_area_height) {
1575 DRM_ERROR("Invalid dimensions for mixer layer 0.\n");
1581 ret = xlnx_mix_set_layer_dimensions(plane, crtc_x, crtc_y,
1582 src_w, src_h, luma_stride);
1586 if (!plane->mixer_layer->hw_config.is_streaming)
1587 ret = xlnx_mix_set_layer_buff_addr
1589 plane->mixer_layer->id,
1590 luma_addr, chroma_addr);
1595 /* mode set a plane */
1596 static int xlnx_mix_plane_mode_set(struct drm_plane *base_plane,
1597 struct drm_framebuffer *fb,
1598 int crtc_x, int crtc_y,
1599 unsigned int crtc_w, unsigned int crtc_h,
1600 u32 src_x, uint32_t src_y,
1601 u32 src_w, uint32_t src_h)
1603 struct xlnx_mix_plane *plane = to_xlnx_plane(base_plane);
1604 const struct drm_format_info *info = fb->format;
1606 dma_addr_t luma_paddr;
1610 /* JPM TODO begin start of code to extract into prep-interleaved*/
1611 DRM_DEBUG_KMS("plane->id: %d\n", plane->id);
1612 DRM_DEBUG_KMS("h: %d(%d), v: %d(%d)\n", src_w, crtc_x, src_h, crtc_y);
1614 /* We have multiple dma channels. Set each per video plane */
1615 for (; i < info->num_planes; i++) {
1616 unsigned int width = src_w / (i ? info->hsub : 1);
1617 unsigned int height = src_h / (i ? info->vsub : 1);
1619 luma_paddr = drm_fb_cma_get_gem_addr(fb, base_plane->state, i);
1621 DRM_ERROR("%s failed to get luma paddr\n", __func__);
1625 plane->dma[i].xt.numf = height;
1626 plane->dma[i].sgl[0].size =
1627 drm_format_plane_width_bytes(info, 0, width);
1628 plane->dma[i].sgl[0].icg = fb->pitches[0] -
1629 plane->dma[i].sgl[0].size;
1630 plane->dma[i].xt.src_start = luma_paddr;
1631 plane->dma[i].xt.frame_size = info->num_planes;
1632 plane->dma[i].xt.dir = DMA_MEM_TO_DEV;
1633 plane->dma[i].xt.src_sgl = true;
1634 plane->dma[i].xt.dst_sgl = false;
1635 plane->dma[i].is_active = true;
1638 for (; i < XVMIX_MAX_NUM_SUB_PLANES; i++)
1639 plane->dma[i].is_active = false;
1640 /* Do we have a video format aware dma channel?
1641 * If so, modify descriptor accordingly
1643 if (plane->dma[0].chan && !plane->dma[1].chan && info->num_planes > 1) {
1644 stride = plane->dma[0].sgl[0].size + plane->dma[0].sgl[0].icg;
1645 plane->dma[0].sgl[0].src_icg = plane->dma[1].xt.src_start -
1646 plane->dma[0].xt.src_start -
1647 (plane->dma[0].xt.numf * stride);
1650 ret = xlnx_mix_set_plane(plane, fb, crtc_x, crtc_y, src_x, src_y,
1655 static int xlnx_mix_plane_prepare_fb(struct drm_plane *plane,
1656 struct drm_plane_state *new_state)
1661 static void xlnx_mix_plane_cleanup_fb(struct drm_plane *plane,
1662 struct drm_plane_state *old_state)
1666 static int xlnx_mix_plane_atomic_check(struct drm_plane *plane,
1667 struct drm_plane_state *state)
1672 static void xlnx_mix_plane_atomic_update(struct drm_plane *plane,
1673 struct drm_plane_state *old_state)
1677 ret = xlnx_mix_plane_mode_set(plane, plane->state->fb,
1678 plane->state->crtc_x,
1679 plane->state->crtc_y,
1680 plane->state->crtc_w,
1681 plane->state->crtc_h,
1682 plane->state->src_x >> 16,
1683 plane->state->src_y >> 16,
1684 plane->state->src_w >> 16,
1685 plane->state->src_h >> 16);
1687 DRM_ERROR("failed to mode-set a plane\n");
1690 /* apply the new fb addr */
1691 xlnx_mix_plane_commit(plane);
1692 /* make sure a plane is on */
1693 xlnx_mix_plane_dpms(plane, DRM_MODE_DPMS_ON);
1696 static void xlnx_mix_plane_atomic_disable(struct drm_plane *plane,
1697 struct drm_plane_state *old_state)
1699 xlnx_mix_plane_dpms(plane, DRM_MODE_DPMS_OFF);
1702 static const struct drm_plane_helper_funcs xlnx_mix_plane_helper_funcs = {
1703 .prepare_fb = xlnx_mix_plane_prepare_fb,
1704 .cleanup_fb = xlnx_mix_plane_cleanup_fb,
1705 .atomic_check = xlnx_mix_plane_atomic_check,
1706 .atomic_update = xlnx_mix_plane_atomic_update,
1707 .atomic_disable = xlnx_mix_plane_atomic_disable,
1710 static int xlnx_mix_init_plane(struct xlnx_mix_plane *plane,
1711 unsigned int poss_crtcs,
1712 struct device_node *layer_node)
1714 struct xlnx_mix *mixer = plane->mixer;
1716 enum drm_plane_type type;
1719 plane->dpms = DRM_MODE_DPMS_OFF;
1720 type = DRM_PLANE_TYPE_OVERLAY;
1722 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++) {
1723 snprintf(name, sizeof(name), "dma%d", i);
1724 plane->dma[i].chan = of_dma_request_slave_channel(layer_node,
1726 if (PTR_ERR(plane->dma[i].chan) == -ENODEV) {
1727 plane->dma[i].chan = NULL;
1730 if (IS_ERR(plane->dma[i].chan)) {
1731 DRM_ERROR("failed to request dma channel\n");
1732 ret = PTR_ERR(plane->dma[i].chan);
1733 plane->dma[i].chan = NULL;
1737 if (!xlnx_mix_isfmt_support(plane->mixer_layer->hw_config.vid_fmt)) {
1738 DRM_ERROR("DRM color format not supported by mixer\n");
1742 plane->format = plane->mixer_layer->hw_config.vid_fmt;
1743 if (plane == mixer->hw_logo_layer)
1744 type = DRM_PLANE_TYPE_CURSOR;
1745 if (plane == mixer->drm_primary_layer)
1746 type = DRM_PLANE_TYPE_PRIMARY;
1748 /* initialize drm plane */
1749 ret = drm_universal_plane_init(mixer->drm, &plane->base,
1750 poss_crtcs, &xlnx_mix_plane_funcs,
1752 1, NULL, type, NULL);
1755 DRM_ERROR("failed to initialize plane\n");
1758 drm_plane_helper_add(&plane->base, &xlnx_mix_plane_helper_funcs);
1759 of_node_put(layer_node);
1764 xlnx_mix_disp_layer_disable(plane);
1766 for (i = 0; i < XVMIX_MAX_NUM_SUB_PLANES; i++)
1767 if (plane->dma[i].chan)
1768 dma_release_channel(plane->dma[i].chan);
1770 of_node_put(layer_node);
1774 static int xlnx_mix_parse_dt_bg_video_fmt(struct device_node *node,
1775 struct xlnx_mix_hw *mixer_hw)
1777 struct device_node *layer_node;
1778 struct xlnx_mix_layer_data *layer;
1779 const char *vformat;
1781 layer_node = of_get_child_by_name(node, "layer_0");
1782 layer = &mixer_hw->layer_data[XVMIX_MASTER_LAYER_IDX];
1784 /* Set default values */
1785 layer->hw_config.can_alpha = false;
1786 layer->hw_config.can_scale = false;
1787 layer->hw_config.min_width = XVMIX_LAYER_WIDTH_MIN;
1788 layer->hw_config.min_height = XVMIX_LAYER_HEIGHT_MIN;
1790 if (of_property_read_string(layer_node, "xlnx,vformat",
1792 DRM_ERROR("No xlnx,vformat value for layer 0 in dts\n");
1795 strcpy((char *)&layer->hw_config.vid_fmt, vformat);
1796 layer->hw_config.is_streaming =
1797 of_property_read_bool(layer_node, "xlnx,layer-streaming");
1798 if (of_property_read_u32(node, "xlnx,bpc", &mixer_hw->bg_layer_bpc)) {
1799 DRM_ERROR("Failed to get bits per component (bpc) prop\n");
1802 if (of_property_read_u32(layer_node, "xlnx,layer-max-width",
1803 &layer->hw_config.max_width)) {
1804 DRM_ERROR("Failed to get screen width prop\n");
1807 mixer_hw->max_layer_width = layer->hw_config.max_width;
1808 if (of_property_read_u32(layer_node, "xlnx,layer-max-height",
1809 &layer->hw_config.max_height)) {
1810 DRM_ERROR("Failed to get screen height prop\n");
1813 mixer_hw->max_layer_height = layer->hw_config.max_height;
1814 layer->id = XVMIX_LAYER_MASTER;
1819 static int xlnx_mix_parse_dt_logo_data(struct device_node *node,
1820 struct xlnx_mix_hw *mixer_hw)
1822 struct xlnx_mix_layer_data *layer_data;
1823 struct device_node *logo_node;
1824 u32 max_width, max_height;
1826 logo_node = of_get_child_by_name(node, "logo");
1828 DRM_ERROR("No logo node specified in device tree.\n");
1832 layer_data = &mixer_hw->layer_data[XVMIX_LOGO_LAYER_IDX];
1834 /* set defaults for logo layer */
1835 layer_data->hw_config.min_height = XVMIX_LOGO_LAYER_HEIGHT_MIN;
1836 layer_data->hw_config.min_width = XVMIX_LOGO_LAYER_WIDTH_MIN;
1837 layer_data->hw_config.is_streaming = false;
1838 layer_data->hw_config.vid_fmt = DRM_FORMAT_RGB888;
1839 layer_data->hw_config.can_alpha = true;
1840 layer_data->hw_config.can_scale = true;
1841 layer_data->layer_regs.buff_addr1 = 0;
1842 layer_data->layer_regs.buff_addr2 = 0;
1843 layer_data->id = XVMIX_LAYER_LOGO;
1845 if (of_property_read_u32(logo_node, "xlnx,logo-width", &max_width)) {
1846 DRM_ERROR("Failed to get logo width prop\n");
1849 if (max_width > XVMIX_LOGO_LAYER_WIDTH_MAX ||
1850 max_width < XVMIX_LOGO_LAYER_WIDTH_MIN) {
1851 DRM_ERROR("Illegal mixer logo layer width.\n");
1854 layer_data->hw_config.max_width = max_width;
1855 mixer_hw->max_logo_layer_width = layer_data->hw_config.max_width;
1857 if (of_property_read_u32(logo_node, "xlnx,logo-height", &max_height)) {
1858 DRM_ERROR("Failed to get logo height prop\n");
1861 if (max_height > XVMIX_LOGO_LAYER_HEIGHT_MAX ||
1862 max_height < XVMIX_LOGO_LAYER_HEIGHT_MIN) {
1863 DRM_ERROR("Illegal mixer logo layer height.\n");
1866 layer_data->hw_config.max_height = max_height;
1867 mixer_hw->max_logo_layer_height = layer_data->hw_config.max_height;
1868 mixer_hw->logo_pixel_alpha_enabled =
1869 of_property_read_bool(logo_node, "xlnx,logo-pixel-alpha");
1870 if (mixer_hw->logo_pixel_alpha_enabled)
1871 layer_data->hw_config.vid_fmt = DRM_FORMAT_RGBA8888;
1876 static int xlnx_mix_dt_parse(struct device *dev, struct xlnx_mix *mixer)
1878 struct xlnx_mix_plane *planes;
1879 struct xlnx_mix_hw *mixer_hw;
1880 struct device_node *node;
1881 struct xlnx_mix_layer_data *l_data;
1882 struct resource res;
1885 node = dev->of_node;
1886 mixer_hw = &mixer->mixer_hw;
1887 mixer->dpms = DRM_MODE_DPMS_OFF;
1889 mixer_hw->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
1890 if (IS_ERR(mixer_hw->reset_gpio)) {
1891 ret = PTR_ERR(mixer_hw->reset_gpio);
1892 if (ret == -EPROBE_DEFER)
1893 dev_dbg(dev, "No gpio probed for mixer. Deferring\n");
1895 dev_err(dev, "No reset gpio info from dts for mixer\n");
1899 ret = of_address_to_resource(node, 0, &res);
1901 dev_err(dev, "Invalid memory address for mixer %d\n", ret);
1904 /* Read in mandatory global dts properties */
1905 mixer_hw->base = devm_ioremap_resource(dev, &res);
1906 if (IS_ERR(mixer_hw->base)) {
1907 dev_err(dev, "Failed to map io mem space for mixer\n");
1908 return PTR_ERR(mixer_hw->base);
1910 ret = of_property_read_u32(node, "xlnx,num-layers",
1911 &mixer_hw->max_layers);
1913 dev_err(dev, "No xlnx,num-layers dts prop for mixer node\n");
1916 if (mixer_hw->max_layers > XVMIX_MAX_LAYERS) {
1917 dev_err(dev, "Num layer nodes in device tree > mixer max\n");
1920 ret = of_property_read_u32(node, "xlnx,dma-addr-width",
1921 &mixer_hw->dma_addr_size);
1923 dev_err(dev, "missing addr-width dts prop\n");
1926 if (mixer_hw->dma_addr_size != 32 && mixer_hw->dma_addr_size != 64) {
1927 dev_err(dev, "invalid addr-width dts prop\n");
1930 mixer_hw->logo_layer_en = of_property_read_bool(node,
1932 l_cnt = mixer_hw->max_layers + (mixer_hw->logo_layer_en ? 1 : 0);
1933 mixer_hw->layer_cnt = l_cnt;
1935 l_data = devm_kzalloc(dev, sizeof(*l_data) * l_cnt, GFP_KERNEL);
1938 mixer_hw->layer_data = l_data;
1939 /* init DRM planes */
1940 planes = devm_kzalloc(dev, sizeof(*planes) * l_cnt, GFP_KERNEL);
1943 mixer->planes = planes;
1944 mixer->num_planes = l_cnt;
1945 for (i = 0; i < mixer->num_planes; i++)
1946 mixer->planes[i].mixer = mixer;
1948 /* establish background layer video properties from dts */
1949 ret = xlnx_mix_parse_dt_bg_video_fmt(node, mixer_hw);
1952 /* read logo data from dts */
1953 ret = xlnx_mix_parse_dt_logo_data(node, mixer_hw);
1958 static int xlnx_mix_of_init_layer(struct device *dev, struct device_node *node,
1959 char *name, struct xlnx_mix_layer_data *layer,
1960 u32 max_width, struct xlnx_mix *mixer, int id)
1962 struct device_node *layer_node;
1963 const char *vformat;
1966 layer_node = of_get_child_by_name(node, name);
1970 /* Set default values */
1971 layer->hw_config.can_alpha = false;
1972 layer->hw_config.can_scale = false;
1973 layer->hw_config.is_streaming = false;
1974 layer->hw_config.max_width = max_width;
1975 layer->hw_config.min_width = XVMIX_LAYER_WIDTH_MIN;
1976 layer->hw_config.min_height = XVMIX_LAYER_HEIGHT_MIN;
1977 layer->hw_config.vid_fmt = 0;
1979 mixer->planes[id].mixer_layer = layer;
1981 ret = of_property_read_u32(layer_node, "xlnx,layer-id", &layer->id);
1983 dev_err(dev, "xlnx,layer-id property not found\n");
1986 if (layer->id < 1 || layer->id >= XVMIX_MAX_LAYERS) {
1987 dev_err(dev, "Mixer layer id %u in dts is out of legal range\n",
1991 ret = of_property_read_string(layer_node, "xlnx,vformat", &vformat);
1993 dev_err(dev, "No mixer layer vformat in dts for layer id %d\n",
1998 strcpy((char *)&layer->hw_config.vid_fmt, vformat);
1999 layer->hw_config.can_scale =
2000 of_property_read_bool(layer_node, "xlnx,layer-scale");
2001 if (layer->hw_config.can_scale) {
2002 ret = of_property_read_u32(layer_node, "xlnx,layer-max-width",
2003 &layer->hw_config.max_width);
2005 dev_err(dev, "Mixer layer %d dts missing width prop.\n",
2010 if (layer->hw_config.max_width > max_width) {
2011 dev_err(dev, "Illlegal Mixer layer %d width %d\n",
2012 layer->id, layer->hw_config.max_width);
2016 layer->hw_config.can_alpha =
2017 of_property_read_bool(layer_node, "xlnx,layer-alpha");
2018 layer->hw_config.is_streaming =
2019 of_property_read_bool(layer_node, "xlnx,layer-streaming");
2020 if (of_property_read_bool(layer_node, "xlnx,layer-primary")) {
2021 if (mixer->drm_primary_layer) {
2023 "More than one primary layer in mixer dts\n");
2026 mixer->drm_primary_layer = &mixer->planes[id];
2028 ret = xlnx_mix_init_plane(&mixer->planes[id], 1, layer_node);
2030 dev_err(dev, "Unable to init drm mixer plane id = %u", id);
2035 static irqreturn_t xlnx_mix_intr_handler(int irq, void *data)
2037 struct xlnx_mix_hw *mixer = data;
2038 u32 intr = xlnx_mix_get_intr_status(mixer);
2042 if (mixer->intrpt_handler_fn)
2043 mixer->intrpt_handler_fn(mixer->intrpt_data);
2044 xlnx_mix_clear_intr_status(mixer, intr);
2049 static void xlnx_mix_create_plane_properties(struct xlnx_mix *mixer)
2051 mixer->scale_prop = drm_property_create_range(mixer->drm, 0, "scale",
2052 XVMIX_SCALE_FACTOR_1X,
2053 XVMIX_SCALE_FACTOR_4X);
2054 mixer->alpha_prop = drm_property_create_range(mixer->drm, 0, "alpha",
2059 static int xlnx_mix_plane_create(struct device *dev, struct xlnx_mix *mixer)
2061 struct xlnx_mix_hw *mixer_hw;
2062 struct device_node *node, *layer_node;
2064 struct xlnx_mix_layer_data *layer_data;
2068 node = dev->of_node;
2069 mixer_hw = &mixer->mixer_hw;
2070 xlnx_mix_create_plane_properties(mixer);
2072 mixer->planes[XVMIX_MASTER_LAYER_IDX].mixer_layer =
2073 &mixer_hw->layer_data[XVMIX_MASTER_LAYER_IDX];
2074 mixer->planes[XVMIX_MASTER_LAYER_IDX].id = XVMIX_MASTER_LAYER_IDX;
2075 mixer->hw_master_layer = &mixer->planes[XVMIX_MASTER_LAYER_IDX];
2077 if (mixer_hw->logo_layer_en) {
2078 mixer->planes[XVMIX_LOGO_LAYER_IDX].mixer_layer =
2079 &mixer_hw->layer_data[XVMIX_LOGO_LAYER_IDX];
2080 mixer->planes[XVMIX_LOGO_LAYER_IDX].id = XVMIX_LOGO_LAYER_IDX;
2081 mixer->hw_logo_layer = &mixer->planes[XVMIX_LOGO_LAYER_IDX];
2082 layer_node = of_get_child_by_name(node, "logo");
2083 ret = xlnx_mix_init_plane(&mixer->planes[XVMIX_LOGO_LAYER_IDX],
2088 layer_idx = mixer_hw->logo_layer_en ? 2 : 1;
2089 for (i = 1; i < mixer_hw->max_layers; i++, layer_idx++) {
2090 snprintf(name, sizeof(name), "layer_%d", i);
2091 ret = xlnx_mix_of_init_layer(dev, node, name,
2092 &mixer_hw->layer_data[layer_idx],
2093 mixer_hw->max_layer_width,
2098 /* If none of the overlay layers were designated as the drm
2099 * primary layer, default to the mixer's video0 layer as drm primary
2101 if (!mixer->drm_primary_layer)
2102 mixer->drm_primary_layer = mixer->hw_master_layer;
2103 layer_node = of_get_child_by_name(node, "layer_0");
2104 ret = xlnx_mix_init_plane(&mixer->planes[XVMIX_MASTER_LAYER_IDX], 1,
2106 /* request irq and obtain pixels-per-clock (ppc) property */
2107 mixer_hw->irq = irq_of_parse_and_map(node, 0);
2108 if (mixer_hw->irq > 0) {
2109 ret = devm_request_irq(dev, mixer_hw->irq,
2110 xlnx_mix_intr_handler,
2111 IRQF_SHARED, "xlnx-mixer", mixer_hw);
2113 dev_err(dev, "Failed to request irq\n");
2117 ret = of_property_read_u32(node, "xlnx,ppc", &mixer_hw->ppc);
2119 dev_err(dev, "No xlnx,ppc property for mixer dts\n");
2123 mixer->max_width = XVMIX_DISP_MAX_WIDTH;
2124 mixer->max_height = XVMIX_DISP_MAX_HEIGHT;
2125 if (mixer->hw_logo_layer) {
2126 layer_data = &mixer_hw->layer_data[XVMIX_LOGO_LAYER_IDX];
2127 mixer->max_cursor_width = layer_data->hw_config.max_width;
2128 mixer->max_cursor_height = layer_data->hw_config.max_height;
2134 * xlnx_mix_plane_restore - Restore the plane states
2135 * @mixer: mixer device core structure
2137 * Restore the plane states to the default ones. Any state that needs to be
2138 * restored should be here. This improves consistency as applications see
2139 * the same default values, and removes mismatch between software and hardware
2140 * values as software values are updated as hardware values are reset.
2142 static void xlnx_mix_plane_restore(struct xlnx_mix *mixer)
2144 struct xlnx_mix_plane *plane;
2150 * Reinitialize property default values as they get reset by DPMS OFF
2151 * operation. User will read the correct default values later, and
2152 * planes will be initialized with default values.
2154 for (i = 0; i < mixer->num_planes; i++) {
2155 plane = &mixer->planes[i];
2158 xlnx_mix_hw_plane_dpms(plane, DRM_MODE_DPMS_OFF);
2163 * xlnx_mix_set_bkg_col - Set background color
2164 * @mixer: Mixer instance to program with new background color
2165 * @rgb_value: RGB encoded as 32-bit integer in little-endian format
2167 * Set the color to be output as background color when background stream layer
2169 static void xlnx_mix_set_bkg_col(struct xlnx_mix_hw *mixer, u64 rgb_value)
2171 u32 bg_bpc = mixer->bg_layer_bpc;
2172 u32 bpc_mask_shift = XVMIX_MAX_BPC - bg_bpc;
2173 u32 val_mask = (GENMASK(15, 0) >> bpc_mask_shift);
2174 u16 b_val = (rgb_value >> (bg_bpc * 2)) & val_mask;
2175 u16 g_val = (rgb_value >> bg_bpc) & val_mask;
2176 u16 r_val = (rgb_value >> 0) & val_mask;
2178 /* Set Background Color */
2179 reg_writel(mixer->base, XVMIX_BACKGROUND_Y_R_DATA, r_val);
2180 reg_writel(mixer->base, XVMIX_BACKGROUND_U_G_DATA, g_val);
2181 reg_writel(mixer->base, XVMIX_BACKGROUND_V_B_DATA, b_val);
2182 mixer->bg_color = rgb_value;
2186 * xlnx_mix_reset - Reset the mixer core video generator
2187 * @mixer: Mixer core instance for which to start video output
2189 * Toggle the reset gpio and restores the bg color, plane and interrupt mask.
2191 static void xlnx_mix_reset(struct xlnx_mix *mixer)
2193 struct xlnx_mix_hw *mixer_hw = &mixer->mixer_hw;
2195 gpiod_set_raw_value(mixer_hw->reset_gpio, 0);
2196 gpiod_set_raw_value(mixer_hw->reset_gpio, 1);
2197 /* restore layer properties and bg color after reset */
2198 xlnx_mix_set_bkg_col(mixer_hw, mixer_hw->bg_color);
2199 xlnx_mix_plane_restore(mixer);
2200 xlnx_mix_intrpt_enable_done(&mixer->mixer_hw);
2203 static void xlnx_mix_dpms(struct xlnx_mix *mixer, int dpms)
2206 case DRM_MODE_DPMS_ON:
2207 xlnx_mix_start(&mixer->mixer_hw);
2210 xlnx_mix_stop(&mixer->mixer_hw);
2211 mdelay(50); /* let IP shut down */
2212 xlnx_mix_reset(mixer);
2217 static void xlnx_mix_crtc_dpms(struct drm_crtc *base_crtc, int dpms)
2219 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2220 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2223 DRM_DEBUG_KMS("dpms: %d\n", dpms);
2224 if (mixer->dpms == dpms)
2229 case DRM_MODE_DPMS_ON:
2230 if (!mixer->pixel_clock_enabled) {
2231 ret = clk_prepare_enable(mixer->pixel_clock);
2233 DRM_ERROR("failed to enable a pixel clock\n");
2234 mixer->pixel_clock_enabled = false;
2237 mixer->pixel_clock_enabled = true;
2239 xlnx_mix_dpms(mixer, dpms);
2240 xlnx_mix_plane_dpms(base_crtc->primary, dpms);
2243 xlnx_mix_plane_dpms(base_crtc->primary, dpms);
2244 xlnx_mix_dpms(mixer, dpms);
2245 if (mixer->pixel_clock_enabled) {
2246 clk_disable_unprepare(mixer->pixel_clock);
2247 mixer->pixel_clock_enabled = false;
2253 static void xlnx_mix_set_intr_handler(struct xlnx_mix *mixer,
2254 void (*intr_handler_fn)(void *),
2257 mixer->mixer_hw.intrpt_handler_fn = intr_handler_fn;
2258 mixer->mixer_hw.intrpt_data = data;
2261 static void xlnx_mix_crtc_vblank_handler(void *data)
2263 struct drm_crtc *base_crtc = data;
2264 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2265 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2266 struct drm_device *drm = base_crtc->dev;
2267 struct drm_pending_vblank_event *event;
2268 unsigned long flags;
2270 drm_crtc_handle_vblank(base_crtc);
2271 /* Finish page flip */
2272 spin_lock_irqsave(&drm->event_lock, flags);
2273 event = mixer->event;
2274 mixer->event = NULL;
2276 drm_crtc_send_vblank_event(base_crtc, event);
2277 drm_crtc_vblank_put(base_crtc);
2279 spin_unlock_irqrestore(&drm->event_lock, flags);
2282 static int xlnx_mix_crtc_enable_vblank(struct drm_crtc *base_crtc)
2284 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2285 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2287 xlnx_mix_set_intr_handler(mixer, xlnx_mix_crtc_vblank_handler,
2292 static void xlnx_mix_crtc_disable_vblank(struct drm_crtc *base_crtc)
2294 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2295 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2297 mixer->mixer_hw.intrpt_handler_fn = NULL;
2298 mixer->mixer_hw.intrpt_data = NULL;
2301 static void xlnx_mix_crtc_destroy(struct drm_crtc *base_crtc)
2303 struct xlnx_crtc *crtc = to_xlnx_crtc(base_crtc);
2304 struct xlnx_mix *mixer = to_xlnx_mixer(crtc);
2306 /* make sure crtc is off */
2307 mixer->alpha_prop = NULL;
2308 mixer->scale_prop = NULL;
2309 mixer->bg_color = NULL;
2310 xlnx_mix_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF);
2312 if (mixer->pixel_clock_enabled) {
2313 clk_disable_unprepare(mixer->pixel_clock);
2314 mixer->pixel_clock_enabled = false;
2316 drm_crtc_cleanup(base_crtc);
2320 xlnx_mix_disp_crtc_atomic_set_property(struct drm_crtc *crtc,
2321 struct drm_crtc_state *state,
2322 struct drm_property *property,
2329 xlnx_mix_disp_crtc_atomic_get_property(struct drm_crtc *crtc,
2330 const struct drm_crtc_state *state,
2331 struct drm_property *property,
2337 static struct drm_crtc_funcs xlnx_mix_crtc_funcs = {
2338 .destroy = xlnx_mix_crtc_destroy,
2339 .set_config = drm_atomic_helper_set_config,
2340 .page_flip = drm_atomic_helper_page_flip,
2341 .atomic_set_property = xlnx_mix_disp_crtc_atomic_set_property,
2342 .atomic_get_property = xlnx_mix_disp_crtc_atomic_get_property,
2343 .reset = drm_atomic_helper_crtc_reset,
2344 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
2345 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
2346 .enable_vblank = xlnx_mix_crtc_enable_vblank,
2347 .disable_vblank = xlnx_mix_crtc_disable_vblank,
2351 xlnx_mix_crtc_atomic_enable(struct drm_crtc *crtc,
2352 struct drm_crtc_state *old_crtc_state)
2354 xlnx_mix_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
2358 * xlnx_mix_clear_event - Clear any event if pending
2359 * @crtc: DRM crtc object
2362 static void xlnx_mix_clear_event(struct drm_crtc *crtc)
2364 if (crtc->state->event) {
2365 complete_all(crtc->state->event->base.completion);
2366 crtc->state->event = NULL;
2371 xlnx_mix_crtc_atomic_disable(struct drm_crtc *crtc,
2372 struct drm_crtc_state *old_crtc_state)
2374 xlnx_mix_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
2375 xlnx_mix_clear_event(crtc);
2378 static void xlnx_mix_crtc_mode_set_nofb(struct drm_crtc *crtc)
2382 static int xlnx_mix_crtc_atomic_check(struct drm_crtc *crtc,
2383 struct drm_crtc_state *state)
2385 return drm_atomic_add_affected_planes(state->state, crtc);
2389 xlnx_mix_crtc_atomic_begin(struct drm_crtc *crtc,
2390 struct drm_crtc_state *old_crtc_state)
2392 /* Don't rely on vblank when disabling crtc */
2393 if (crtc->state->event) {
2394 struct xlnx_crtc *xcrtc = to_xlnx_crtc(crtc);
2395 struct xlnx_mix *mixer = to_xlnx_mixer(xcrtc);
2397 /* Consume the flip_done event from atomic helper */
2398 crtc->state->event->pipe = drm_crtc_index(crtc);
2399 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
2400 mixer->event = crtc->state->event;
2401 crtc->state->event = NULL;
2405 static struct drm_crtc_helper_funcs xlnx_mix_crtc_helper_funcs = {
2406 .atomic_enable = xlnx_mix_crtc_atomic_enable,
2407 .atomic_disable = xlnx_mix_crtc_atomic_disable,
2408 .mode_set_nofb = xlnx_mix_crtc_mode_set_nofb,
2409 .atomic_check = xlnx_mix_crtc_atomic_check,
2410 .atomic_begin = xlnx_mix_crtc_atomic_begin,
2414 * xlnx_mix_crtc_create - create crtc for mixer
2415 * @mixer: xilinx video mixer object
2418 * Zero on success, error on failure
2421 static int xlnx_mix_crtc_create(struct xlnx_mix *mixer)
2423 struct xlnx_crtc *crtc;
2424 struct drm_plane *primary_plane = NULL;
2425 struct drm_plane *cursor_plane = NULL;
2428 crtc = &mixer->crtc;
2429 primary_plane = &mixer->drm_primary_layer->base;
2430 cursor_plane = &mixer->hw_logo_layer->base;
2432 for (i = 0; i < mixer->num_planes; i++)
2433 xlnx_mix_attach_plane_prop(&mixer->planes[i]);
2434 mixer->pixel_clock = devm_clk_get(mixer->drm->dev, NULL);
2435 if (IS_ERR(mixer->pixel_clock)) {
2436 DRM_DEBUG_KMS("failed to get pixel clock\n");
2437 mixer->pixel_clock = NULL;
2439 ret = clk_prepare_enable(mixer->pixel_clock);
2441 DRM_ERROR("failed to enable a pixel clock\n");
2442 mixer->pixel_clock_enabled = false;
2445 mixer->pixel_clock_enabled = true;
2446 /* initialize drm crtc */
2447 ret = drm_crtc_init_with_planes(mixer->drm, &crtc->crtc,
2448 &mixer->drm_primary_layer->base,
2449 &mixer->hw_logo_layer->base,
2450 &xlnx_mix_crtc_funcs, NULL);
2452 DRM_ERROR("failed to initialize mixer crtc\n");
2455 drm_crtc_helper_add(&crtc->crtc, &xlnx_mix_crtc_helper_funcs);
2456 crtc->get_max_width = &xlnx_mix_crtc_get_max_width;
2457 crtc->get_max_height = &xlnx_mix_crtc_get_max_height;
2458 crtc->get_align = &xlnx_mix_crtc_get_align;
2459 crtc->get_format = &xlnx_mix_crtc_get_format;
2460 crtc->get_cursor_height = &xlnx_mix_crtc_get_max_cursor_height;
2461 crtc->get_cursor_width = &xlnx_mix_crtc_get_max_cursor_width;
2462 xlnx_crtc_register(mixer->drm, crtc);
2467 if (mixer->pixel_clock_enabled) {
2468 clk_disable_unprepare(mixer->pixel_clock);
2469 mixer->pixel_clock_enabled = false;
2476 * xlnx_mix_init - Establishes a default power-on state for the mixer IP
2478 * @mixer: instance of IP core to initialize to a default state
2480 * Background layer initialized to maximum height and width settings based on
2481 * device tree properties and all overlay layers set to minimum height and width
2482 * sizes and positioned to 0,0 in the crtc. All layers are inactive (resulting
2483 * in video output being generated by the background color generator).
2484 * Interrupts are disabled and the IP is started (with auto-restart enabled).
2486 static void xlnx_mix_init(struct xlnx_mix_hw *mixer)
2489 u32 bg_bpc = mixer->bg_layer_bpc;
2490 u64 rgb_bg_clr = (0xFFFF >> (XVMIX_MAX_BPC - bg_bpc)) << (bg_bpc * 2);
2491 enum xlnx_mix_layer_id layer_id;
2492 struct xlnx_mix_layer_data *layer_data;
2494 layer_data = xlnx_mix_get_layer_data(mixer, XVMIX_LAYER_MASTER);
2495 xlnx_mix_layer_disable(mixer, XVMIX_LAYER_ALL);
2496 xlnx_mix_set_active_area(mixer, layer_data->hw_config.max_width,
2497 layer_data->hw_config.max_height);
2498 /* default to blue */
2499 xlnx_mix_set_bkg_col(mixer, rgb_bg_clr);
2501 for (i = 0; i < mixer->layer_cnt; i++) {
2502 layer_id = mixer->layer_data[i].id;
2503 layer_data = &mixer->layer_data[i];
2504 if (layer_id == XVMIX_LAYER_MASTER)
2506 xlnx_mix_set_layer_window(mixer, layer_id, 0, 0,
2507 XVMIX_LAYER_WIDTH_MIN,
2508 XVMIX_LAYER_HEIGHT_MIN, 0);
2509 if (layer_data->hw_config.can_scale)
2510 xlnx_mix_set_layer_scaling(mixer, layer_id, 0);
2511 if (layer_data->hw_config.can_alpha)
2512 xlnx_mix_set_layer_alpha(mixer, layer_id,
2515 xlnx_mix_intrpt_enable_done(mixer);
2518 static int xlnx_mix_bind(struct device *dev, struct device *master,
2521 struct xlnx_mix *mixer = dev_get_drvdata(dev);
2522 struct drm_device *drm = data;
2526 ret = xlnx_mix_plane_create(dev, mixer);
2529 ret = xlnx_mix_crtc_create(mixer);
2532 xlnx_mix_init(&mixer->mixer_hw);
2537 static void xlnx_mix_unbind(struct device *dev, struct device *master,
2540 struct xlnx_mix *mixer = dev_get_drvdata(dev);
2542 dev_set_drvdata(dev, NULL);
2543 xlnx_mix_intrpt_disable(&mixer->mixer_hw);
2544 xlnx_crtc_unregister(mixer->drm, &mixer->crtc);
2547 static const struct component_ops xlnx_mix_component_ops = {
2548 .bind = xlnx_mix_bind,
2549 .unbind = xlnx_mix_unbind,
2552 static int xlnx_mix_probe(struct platform_device *pdev)
2554 struct xlnx_mix *mixer;
2557 mixer = devm_kzalloc(&pdev->dev, sizeof(*mixer), GFP_KERNEL);
2561 /* Sub-driver will access mixer from drvdata */
2562 platform_set_drvdata(pdev, mixer);
2563 ret = xlnx_mix_dt_parse(&pdev->dev, mixer);
2565 if (ret != -EPROBE_DEFER)
2566 dev_err(&pdev->dev, "Failed to probe mixer\n");
2570 ret = component_add(&pdev->dev, &xlnx_mix_component_ops);
2574 mixer->master = xlnx_drm_pipeline_init(pdev);
2575 if (IS_ERR(mixer->master)) {
2576 dev_err(&pdev->dev, "Failed to initialize the drm pipeline\n");
2580 dev_info(&pdev->dev, "Xilinx Mixer driver probed success\n");
2584 component_del(&pdev->dev, &xlnx_mix_component_ops);
2589 static int xlnx_mix_remove(struct platform_device *pdev)
2591 struct xlnx_mix *mixer = platform_get_drvdata(pdev);
2593 xlnx_drm_pipeline_exit(mixer->master);
2594 component_del(&pdev->dev, &xlnx_mix_component_ops);
2598 static const struct of_device_id xlnx_mix_of_match[] = {
2599 { .compatible = "xlnx,mixer-3.0", },
2600 { /* end of table */ },
2602 MODULE_DEVICE_TABLE(of, xlnx_mix_of_match);
2604 static struct platform_driver xlnx_mix_driver = {
2605 .probe = xlnx_mix_probe,
2606 .remove = xlnx_mix_remove,
2608 .name = "xlnx-mixer",
2609 .of_match_table = xlnx_mix_of_match,
2613 module_platform_driver(xlnx_mix_driver);
2615 MODULE_AUTHOR("Saurabh Sengar");
2616 MODULE_DESCRIPTION("Xilinx Mixer Driver");
2617 MODULE_LICENSE("GPL v2");