linux/drivers/gpu/drm/xlnx/xlnx_mixer.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx logicore video mixer driver
   4 *
   5 * Copyright (C) 2017 - 2018 Xilinx, Inc.
   6 *
   7 * Author: Saurabh Sengar <saurabhs@xilinx.com>
   8 *       : Jeffrey Mouroux <jmouroux@xilinx.com>
   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/**************************** 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
  72
  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
 102
 103/*************************** STATIC DATA  ************************************/
 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/*********************** 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)
 132
 133/**
 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
 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 * struct xlnx_mix_layer_data - Describes the hardware configuration of a given
 163 * mixer layer
 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
 169 *  external DMA
 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).
 187 *
 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.
 192 *
 193 * Note:
 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
 196 * properties.
 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 * 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
 231 *  layer
 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
 247 *
 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
 251 * struct.
 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 * 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
 297 *
 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
 301 * hardware.
 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 * struct xlnx_mix_plane_dma - Xilinx drm plane VDMA object
 329 *
 330 * @chan: dma channel
 331 * @xt: dma interleaved configuration template
 332 * @sgl: data chunk for dma_interleaved_template
 333 * @is_active: flag if the DMA is active
 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 * struct xlnx_mix_plane - Xilinx drm plane object
 344 *
 345 * @base: base drm plane object
 346 * @mixer_layer: video mixer hardware layer data instance
 347 * @mixer: mixer DRM object
 348 * @dma: dma object
 349 * @id: plane id
 350 * @dpms: current dpms level
 351 * @format: pixel format
 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 * xlnx_mix_intrpt_enable_done - Enables interrupts
 381 * @mixer: instance of mixer IP core
 382 *
 383 * Enables interrupts in the mixer core
 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        /* 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);
 392}
 393
 394/**
 395 * xlnx_mix_intrpt_disable - Disable interrupts
 396 * @mixer: instance of mixer IP core
 397 *
 398 * Disables interrupts in the mixer core
 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 * xlnx_mix_start - Start the mixer core video generator
 410 * @mixer: Mixer core instance for which to start video output
 411 *
 412 * Starts the core to generate a video frame.
 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 * xlnx_mix_stop - Stop the mixer core video generator
 424 * @mixer: Mixer core instance for which to stop video output
 425 *
 426 * Starts the core to generate a video frame.
 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 * 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
 449 *
 450 * Return:
 451 * Structure containing layer-specific data; NULL upon failure
 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 * 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
 473 *
 474 * Minimum values are 64x64 with maximum values determined by the IP hardware
 475 * design.
 476 *
 477 * Return:
 478 * Zero on success, -EINVAL on failure
 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        /* set resolution */
 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 * 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
 508 *
 509 * Validates if the requested window is within the frame boundary
 510 *
 511 * Return:
 512 * true on success, false on failure
 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        /* Check if window scale factor is set */
 523        if (scale < XVMIX_SCALE_FACTOR_INVALID) {
 524                width  *= scale_factor[scale];
 525                height *= scale_factor[scale];
 526        }
 527
 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))
 531                return true;
 532
 533        DRM_ERROR("Requested plane dimensions can't be set\n");
 534        return false;
 535}
 536
 537/**
 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
 541 *
 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
 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        /* 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,
 556         * turning them on.
 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; /* for inactive layers silently return */
 565
 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);
 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 * xlnx_mix_disp_layer_enable - Enables video output represented by the
 586 * plane object
 587 * @plane: Drm plane object describing video layer to enable
 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 * 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)
 615 *
 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
 619 * layers.
 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 * xlnx_mix_disp_layer_disable - Disables video output represented by the
 646 * plane object
 647 * @plane: Drm plane object describing video layer to disable
 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/* apply mode to plane pipe */
 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        /* 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];
 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 * xlnx_mix_crtc_get_format - Get the current device format
 754 * @crtc: xlnx crtc object
 755 *
 756 * Get the current format of pipeline
 757 *
 758 * Return: the corresponding DRM_FORMAT_XXX
 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 * xlnx_mix_crtc_get_align - Get the alignment value for pitch
 769 * @crtc: xlnx crtc object
 770 *
 771 * Get the alignment value for pitch from the plane
 772 *
 773 * Return: The alignment value if successful, or the error code.
 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 * xlnx_mix_attach_plane_prop - Attach mixer-specific drm property to
 785 * the given plane
 786 * @plane: Xilinx drm plane object to inspect and attach appropriate
 787 *  properties to
 788 *
 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.
 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/*************** DISPLAY ************/
 827
 828/**
 829 * xlnx_mix_get_layer_scaling - Get layer scaling factor
 830 * @mixer: Mixer instance to program with new background color
 831 * @id: Plane id
 832 *
 833 * Applicable only for overlay layers
 834 *
 835 * Return:
 836 * scaling factor of the specified layer
 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: /*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;
 859                }
 860                break;
 861        }
 862        return scale_factor;
 863}
 864
 865/**
 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)
 874 *
 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
 877 *
 878 * Return:
 879 * Zero on success, -EINVAL if position is invalid or -ENODEV if layer
 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: /*Layer1-Layer7*/
 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 * 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.
 963 *
 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)
 967 *
 968 * Return: 0 if successful; Either -EINVAL if coordindate data is invalid
 969 * or -ENODEV if layer data not present
 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 * 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
1013 *
1014 * Sets the scaling factor for the specified video layer
1015 * Not applicable to background stream layer (layer 0)
1016 *
1017 * Return:
1018 * Zero on success, -EINVAL on failure to set scale for layer (likely
1019 * returned if resulting size of layer exceeds dimensions of active
1020 * display area
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: /* Layer0-Layer7 */
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 * 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:
1066 *              0 = 1x
1067 *              1 = 2x
1068 *              2 = 4x
1069 *
1070 * Return:
1071 * Zero on success, either -EINVAL if scale value is illegal or
1072 * -ENODEV if layer does not exist (null)
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 * 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
1102 *
1103 * Set the layer global transparency for a video overlay
1104 * Not applicable to background streaming layer
1105 *
1106 * Return:
1107 * Zero on success, -EINVAL on failure
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: /*Layer1-Layer7*/
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 * 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
1147 *
1148 * Return:
1149 * Zero on success, -EINVAL on failure
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 * 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
1172 *
1173 * Sets the buffer address of the specified layer
1174 * Return:
1175 * Zero on success, -EINVAL on failure
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        /* 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)
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 * 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
1215 *
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
1218 * enable a layer.
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                /* 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);
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                /* 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);
1264                break;
1265        default:
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;
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 * xlnx_mix_disp_plane_atomic_update_plane - plane update using atomic
1318 * @plane: plane object to update
1319 * @crtc: owning CRTC of owning plane
1320 * @fb: framebuffer to flip onto plane
1321 * @crtc_x: x offset of primary plane on crtc
1322 * @crtc_y: y offset of primary plane on crtc
1323 * @crtc_w: width of primary plane rectangle on crtc
1324 * @crtc_h: height of primary plane rectangle on crtc
1325 * @src_x: x offset of @fb for panning
1326 * @src_y: y offset of @fb for panning
1327 * @src_w: width of source rectangle in @fb
1328 * @src_h: height of source rectangle in @fb
1329 * @ctx: lock acquire context
1330 *
1331 * Provides a default plane update handler using the atomic driver interface.
1332 *
1333 * RETURNS:
1334 * Zero on success, error code on failure
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        /* Do async-update if possible */
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 * xlnx_mix_logo_load - Loads mixer's internal bram
1402 * @mixer: Mixer instance to act upon
1403 * @logo_w: Width of logo in pixels
1404 * @logo_h: Height of logo in pixels
1405 * @r_buf: Pointer to byte buffer array of R data values
1406 * @g_buf: Pointer to byte buffer array of G data values
1407 * @b_buf: Pointer to byte buffer array of B data values
1408 * @a_buf: Pointer to byte buffer array of A data values
1409 *
1410 * Loads mixer's internal bram with planar R, G, B and A data
1411 *
1412 * Return:
1413 * Zero on success, -ENODEV if logo layer not enabled; -EINVAL otherwise
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        /* RGBA data should be 32-bit word aligned */
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        /* color comp defaults to offset in RG24 buffer */
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        /* ensure valid conditions for update */
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        /* ensure buffer attributes have changed to indicate new logo
1529         * has been created
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        /* cache buffer address for future comparison */
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 * xlnx_mix_set_plane - Implementation of DRM plane_update callback
1561 * @plane: xlnx_mix_plane object containing references to
1562 *  the base plane and mixer
1563 * @fb: Framebuffer descriptor
1564 * @crtc_x: X position of layer on crtc.  Note, if the plane represents either
1565 *  the master hardware layer (video0) or the layer representing the DRM primary
1566 *  layer, the crtc x/y coordinates are either ignored and/or set to 0/0
1567 *  respectively.
1568 * @crtc_y: Y position of layer.  See description of crtc_x handling
1569 * for more inforation.
1570 * @src_x: x-offset in memory buffer from which to start reading
1571 * @src_y: y-offset in memory buffer from which to start reading
1572 * @src_w: Number of horizontal pixels to read from memory per row
1573 * @src_h: Number of rows of video data to read from memory
1574 *
1575 * Configures a mixer layer to comply with user space SET_PLANE icotl
1576 * call.
1577 *
1578 * Return:
1579 * Zero on success, non-zero linux error code otherwise.
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        /* compute memory data */
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/* mode set a plane */
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        /* JPM TODO begin start of code to extract into prep-interleaved*/
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        /* We have multiple dma channels.  Set each per video plane */
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        /* Do we have a video format aware dma channel?
1713         * If so, modify descriptor accordingly
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        /* apply the new fb addr */
1770        xlnx_mix_plane_commit(plane);
1771        /* make sure a plane is on */
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        /* Update the current state with new configurations */
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        /* initialize drm plane */
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        /* Set default values */
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        /* set defaults for logo layer */
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        /* Read in mandatory global dts properties */
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        /* init DRM planes */
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        /* establish background layer video properties from dts */
2061        ret = xlnx_mix_parse_dt_bg_video_fmt(node, mixer_hw);
2062        if (ret)
2063                return ret;
2064        /* read logo data from dts */
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        /* Set default values */
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        /* If none of the overlay layers were designated as the drm
2211         * primary layer, default to the mixer's video0 layer as drm primary
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        /* request irq and obtain pixels-per-clock (ppc) property */
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 * xlnx_mix_plane_restore - Restore the plane states
2247 * @mixer: mixer device core structure
2248 *
2249 * Restore the plane states to the default ones. Any state that needs to be
2250 * restored should be here. This improves consistency as applications see
2251 * the same default values, and removes mismatch between software and hardware
2252 * values as software values are updated as hardware values are reset.
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         * Reinitialize property default values as they get reset by DPMS OFF
2263         * operation. User will read the correct default values later, and
2264         * planes will be initialized with default values.
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 * xlnx_mix_set_bkg_col - Set background color
2276 * @mixer: Mixer instance to program with new background color
2277 * @rgb_value: RGB encoded as 32-bit integer in little-endian format
2278 *
2279 * Set the color to be output as background color when background stream layer
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        /* Set Background Color */
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 * xlnx_mix_reset - Reset the mixer core video generator
2299 * @mixer: Mixer core instance for which to start video output
2300 *
2301 * Toggle the reset gpio and restores the bg color, plane and interrupt mask.
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        /* restore layer properties and bg color after reset */
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); /* let IP shut down */
2324                xlnx_mix_reset(mixer);
2325        }
2326}
2327
2328/* set crtc dpms */
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        /* Finish page flip */
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        /* make sure crtc is off */
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 * xlnx_mix_clear_event - Clear any event if pending
2471 * @crtc: DRM crtc object
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        /* Don't rely on vblank when disabling crtc */
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                /* Consume the flip_done event from atomic helper */
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 * xlnx_mix_crtc_create - create crtc for mixer
2527 * @mixer: xilinx video mixer object
2528 *
2529 * Return:
2530 * Zero on success, error on failure
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        /* initialize drm crtc */
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 * xlnx_mix_init - Establishes a default power-on state for the mixer IP
2589 * core
2590 * @mixer: instance of IP core to initialize to a default state
2591 *
2592 * Background layer initialized to maximum height and width settings based on
2593 * device tree properties and all overlay layers set to minimum height and width
2594 * sizes and positioned to 0,0 in the crtc.   All layers are inactive (resulting
2595 * in video output being generated by the background color generator).
2596 * Interrupts are disabled and the IP is started (with auto-restart enabled).
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        /* default to blue */
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        /* Sub-driver will access mixer from drvdata */
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        { /* end of table */ },
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