linux/drivers/gpu/drm/xilinx/xilinx_drm_dp_sub.c
<<
>>
Prefs
   1/*
   2 * DisplayPort subsystem support for Xilinx DRM KMS
   3 *
   4 *  Copyright (C) 2015 Xilinx, Inc.
   5 *
   6 *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <drm/drmP.h>
  19#include <drm/drm_crtc.h>
  20#include <drm/drm_crtc_helper.h>
  21#include <drm/drm_fourcc.h>
  22
  23#include <linux/device.h>
  24#include <linux/interrupt.h>
  25#include <linux/irqreturn.h>
  26#include <linux/list.h>
  27#include <linux/module.h>
  28#include <linux/mutex.h>
  29#include <linux/of.h>
  30#include <linux/platform_device.h>
  31
  32#include "xilinx_drm_dp_sub.h"
  33#include "xilinx_drm_drv.h"
  34
  35/* Blender registers */
  36#define XILINX_DP_SUB_V_BLEND_BG_CLR_0                          0x0
  37#define XILINX_DP_SUB_V_BLEND_BG_CLR_1                          0x4
  38#define XILINX_DP_SUB_V_BLEND_BG_CLR_2                          0x8
  39#define XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA                  0xc
  40#define XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA_MASK             0x1fe
  41#define XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT                    0x14
  42#define XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_RGB                0x0
  43#define XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YCBCR444           0x1
  44#define XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YCBCR422           0x2
  45#define XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YONLY              0x3
  46#define XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_XVYCC              0x4
  47#define XILINX_DP_SUB_V_BLEND_OUTPUT_EN_DOWNSAMPLE              BIT(4)
  48#define XILINX_DP_SUB_V_BLEND_LAYER_CONTROL                     0x18
  49#define XILINX_DP_SUB_V_BLEND_LAYER_CONTROL_EN_US               BIT(0)
  50#define XILINX_DP_SUB_V_BLEND_LAYER_CONTROL_RGB                 BIT(1)
  51#define XILINX_DP_SUB_V_BLEND_LAYER_CONTROL_BYPASS              BIT(8)
  52#define XILINX_DP_SUB_V_BLEND_NUM_COEFF                         9
  53#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF0                  0x20
  54#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF1                  0x24
  55#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF2                  0x28
  56#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF3                  0x2c
  57#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF4                  0x30
  58#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF5                  0x34
  59#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF6                  0x38
  60#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF7                  0x3c
  61#define XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF8                  0x40
  62#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF0                     0x44
  63#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF1                     0x48
  64#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF2                     0x4c
  65#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF3                     0x50
  66#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF4                     0x54
  67#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF5                     0x58
  68#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF6                     0x5c
  69#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF7                     0x60
  70#define XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF8                     0x64
  71#define XILINX_DP_SUB_V_BLEND_NUM_OFFSET                        3
  72#define XILINX_DP_SUB_V_BLEND_LUMA_IN1CSC_OFFSET                0x68
  73#define XILINX_DP_SUB_V_BLEND_CR_IN1CSC_OFFSET                  0x6c
  74#define XILINX_DP_SUB_V_BLEND_CB_IN1CSC_OFFSET                  0x70
  75#define XILINX_DP_SUB_V_BLEND_LUMA_OUTCSC_OFFSET                0x74
  76#define XILINX_DP_SUB_V_BLEND_CR_OUTCSC_OFFSET                  0x78
  77#define XILINX_DP_SUB_V_BLEND_CB_OUTCSC_OFFSET                  0x7c
  78#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF0                     0x80
  79#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF1                     0x84
  80#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF2                     0x88
  81#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF3                     0x8c
  82#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF4                     0x90
  83#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF5                     0x94
  84#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF6                     0x98
  85#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF7                     0x9c
  86#define XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF8                     0xa0
  87#define XILINX_DP_SUB_V_BLEND_LUMA_IN2CSC_OFFSET                0xa4
  88#define XILINX_DP_SUB_V_BLEND_CR_IN2CSC_OFFSET                  0xa8
  89#define XILINX_DP_SUB_V_BLEND_CB_IN2CSC_OFFSET                  0xac
  90#define XILINX_DP_SUB_V_BLEND_CHROMA_KEY_ENABLE                 0x1d0
  91#define XILINX_DP_SUB_V_BLEND_CHROMA_KEY_COMP1                  0x1d4
  92#define XILINX_DP_SUB_V_BLEND_CHROMA_KEY_COMP2                  0x1d8
  93#define XILINX_DP_SUB_V_BLEND_CHROMA_KEY_COMP3                  0x1dc
  94
  95/* AV buffer manager registers */
  96#define XILINX_DP_SUB_AV_BUF_FMT                                0x0
  97#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_SHIFT                   0
  98#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_MASK                    (0x1f << 0)
  99#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_UYVY                    (0 << 0)
 100#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_VYUY                    (1 << 0)
 101#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YVYU                    (2 << 0)
 102#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YUYV                    (3 << 0)
 103#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16                    (4 << 0)
 104#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV24                    (5 << 0)
 105#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI                  (6 << 0)
 106#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_MONO                    (7 << 0)
 107#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI2                 (8 << 0)
 108#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YUV444                  (9 << 0)
 109#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGB888                  (10 << 0)
 110#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGBA8880                (11 << 0)
 111#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGB888_10               (12 << 0)
 112#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YUV444_10               (13 << 0)
 113#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI2_10              (14 << 0)
 114#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI_10               (15 << 0)
 115#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16_10                 (16 << 0)
 116#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV24_10                 (17 << 0)
 117#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YONLY_10                (18 << 0)
 118#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16_420                (19 << 0)
 119#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI_420              (20 << 0)
 120#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI2_420             (21 << 0)
 121#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16_420_10             (22 << 0)
 122#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI_420_10           (23 << 0)
 123#define XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI2_420_10          (24 << 0)
 124#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_SHIFT                   8
 125#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_MASK                    (0xf << 8)
 126#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA8888                (0 << 8)
 127#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_ABGR8888                (1 << 8)
 128#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGB888                  (2 << 8)
 129#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_BGR888                  (3 << 8)
 130#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA5551                (4 << 8)
 131#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA4444                (5 << 8)
 132#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGB565                  (6 << 8)
 133#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_8BPP                    (7 << 8)
 134#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_4BPP                    (8 << 8)
 135#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_2BPP                    (9 << 8)
 136#define XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_1BPP                    (10 << 8)
 137#define XILINX_DP_SUB_AV_BUF_NON_LIVE_LATENCY                   0x8
 138#define XILINX_DP_SUB_AV_BUF_CHBUF                              0x10
 139#define XILINX_DP_SUB_AV_BUF_CHBUF_EN                           BIT(0)
 140#define XILINX_DP_SUB_AV_BUF_CHBUF_FLUSH                        BIT(1)
 141#define XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_SHIFT              2
 142#define XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_MASK               (0xf << 2)
 143#define XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_MAX                0xf
 144#define XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_AUD_MAX            0x3
 145#define XILINX_DP_SUB_AV_BUF_STATUS                             0x28
 146#define XILINX_DP_SUB_AV_BUF_STC_CTRL                           0x2c
 147#define XILINX_DP_SUB_AV_BUF_STC_CTRL_EN                        BIT(0)
 148#define XILINX_DP_SUB_AV_BUF_STC_CTRL_EVENT_SHIFT               1
 149#define XILINX_DP_SUB_AV_BUF_STC_CTRL_EVENT_EX_VSYNC            0
 150#define XILINX_DP_SUB_AV_BUF_STC_CTRL_EVENT_EX_VID              1
 151#define XILINX_DP_SUB_AV_BUF_STC_CTRL_EVENT_EX_AUD              2
 152#define XILINX_DP_SUB_AV_BUF_STC_CTRL_EVENT_INT_VSYNC           3
 153#define XILINX_DP_SUB_AV_BUF_STC_INIT_VALUE0                    0x30
 154#define XILINX_DP_SUB_AV_BUF_STC_INIT_VALUE1                    0x34
 155#define XILINX_DP_SUB_AV_BUF_STC_ADJ                            0x38
 156#define XILINX_DP_SUB_AV_BUF_STC_VID_VSYNC_TS0                  0x3c
 157#define XILINX_DP_SUB_AV_BUF_STC_VID_VSYNC_TS1                  0x40
 158#define XILINX_DP_SUB_AV_BUF_STC_EXT_VSYNC_TS0                  0x44
 159#define XILINX_DP_SUB_AV_BUF_STC_EXT_VSYNC_TS1                  0x48
 160#define XILINX_DP_SUB_AV_BUF_STC_CUSTOM_EVENT_TS0               0x4c
 161#define XILINX_DP_SUB_AV_BUF_STC_CUSTOM_EVENT_TS1               0x50
 162#define XILINX_DP_SUB_AV_BUF_STC_CUSTOM_EVENT2_TS0              0x54
 163#define XILINX_DP_SUB_AV_BUF_STC_CUSTOM_EVENT2_TS1              0x58
 164#define XILINX_DP_SUB_AV_BUF_STC_SNAPSHOT0                      0x60
 165#define XILINX_DP_SUB_AV_BUF_STC_SNAPSHOT1                      0x64
 166#define XILINX_DP_SUB_AV_BUF_OUTPUT                             0x70
 167#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_SHIFT                  0
 168#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_MASK                   (0x3 << 0)
 169#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_PL                     (0 << 0)
 170#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_MEM                    (1 << 0)
 171#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_PATTERN                (2 << 0)
 172#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_NONE                   (3 << 0)
 173#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_SHIFT                  2
 174#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_MASK                   (0x3 << 2)
 175#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_DISABLE                (0 << 2)
 176#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_MEM                    (1 << 2)
 177#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_LIVE                   (2 << 2)
 178#define XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_NONE                   (3 << 2)
 179#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_SHIFT                  4
 180#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_MASK                   (0x3 << 4)
 181#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_PL                     (0 << 4)
 182#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_MEM                    (1 << 4)
 183#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_PATTERN                (2 << 4)
 184#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_DISABLE                (3 << 4)
 185#define XILINX_DP_SUB_AV_BUF_OUTPUT_AUD2_EN                     BIT(6)
 186#define XILINX_DP_SUB_AV_BUF_HCOUNT_VCOUNT_INT0                 0x74
 187#define XILINX_DP_SUB_AV_BUF_HCOUNT_VCOUNT_INT1                 0x78
 188#define XILINX_DP_SUB_AV_BUF_PATTERN_GEN_SELECT                 0x100
 189#define XILINX_DP_SUB_AV_BUF_CLK_SRC                            0x120
 190#define XILINX_DP_SUB_AV_BUF_CLK_SRC_VID_FROM_PS                BIT(0)
 191#define XILINX_DP_SUB_AV_BUF_CLK_SRC_AUD_FROM_PS                BIT(1)
 192#define XILINX_DP_SUB_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING        BIT(2)
 193#define XILINX_DP_SUB_AV_BUF_SRST_REG                           0x124
 194#define XILINX_DP_SUB_AV_BUF_SRST_REG_VID_RST                   BIT(1)
 195#define XILINX_DP_SUB_AV_BUF_AUDIO_CH_CONFIG                    0x12c
 196#define XILINX_DP_SUB_AV_BUF_GFX_COMP0_SF                       0x200
 197#define XILINX_DP_SUB_AV_BUF_GFX_COMP1_SF                       0x204
 198#define XILINX_DP_SUB_AV_BUF_GFX_COMP2_SF                       0x208
 199#define XILINX_DP_SUB_AV_BUF_VID_COMP0_SF                       0x20c
 200#define XILINX_DP_SUB_AV_BUF_VID_COMP1_SF                       0x210
 201#define XILINX_DP_SUB_AV_BUF_VID_COMP2_SF                       0x214
 202#define XILINX_DP_SUB_AV_BUF_LIVE_VID_COMP0_SF                  0x218
 203#define XILINX_DP_SUB_AV_BUF_LIVE_VID_COMP1_SF                  0x21c
 204#define XILINX_DP_SUB_AV_BUF_LIVE_VID_COMP2_SF                  0x220
 205#define XILINX_DP_SUB_AV_BUF_4BIT_SF                            0x11111
 206#define XILINX_DP_SUB_AV_BUF_5BIT_SF                            0x10842
 207#define XILINX_DP_SUB_AV_BUF_6BIT_SF                            0x10410
 208#define XILINX_DP_SUB_AV_BUF_8BIT_SF                            0x10101
 209#define XILINX_DP_SUB_AV_BUF_10BIT_SF                           0x10040
 210#define XILINX_DP_SUB_AV_BUF_NULL_SF                            0
 211#define XILINX_DP_SUB_AV_BUF_NUM_SF                             3
 212#define XILINX_DP_SUB_AV_BUF_LIVE_CB_CR_SWAP                    0x224
 213#define XILINX_DP_SUB_AV_BUF_PALETTE_MEMORY                     0x400
 214
 215/* Audio registers */
 216#define XILINX_DP_SUB_AUD_MIXER_VOLUME                          0x0
 217#define XILINX_DP_SUB_AUD_MIXER_VOLUME_NO_SCALE                 0x20002000
 218#define XILINX_DP_SUB_AUD_MIXER_META_DATA                       0x4
 219#define XILINX_DP_SUB_AUD_CH_STATUS0                            0x8
 220#define XILINX_DP_SUB_AUD_CH_STATUS1                            0xc
 221#define XILINX_DP_SUB_AUD_CH_STATUS2                            0x10
 222#define XILINX_DP_SUB_AUD_CH_STATUS3                            0x14
 223#define XILINX_DP_SUB_AUD_CH_STATUS4                            0x18
 224#define XILINX_DP_SUB_AUD_CH_STATUS5                            0x1c
 225#define XILINX_DP_SUB_AUD_CH_A_DATA0                            0x20
 226#define XILINX_DP_SUB_AUD_CH_A_DATA1                            0x24
 227#define XILINX_DP_SUB_AUD_CH_A_DATA2                            0x28
 228#define XILINX_DP_SUB_AUD_CH_A_DATA3                            0x2c
 229#define XILINX_DP_SUB_AUD_CH_A_DATA4                            0x30
 230#define XILINX_DP_SUB_AUD_CH_A_DATA5                            0x34
 231#define XILINX_DP_SUB_AUD_CH_B_DATA0                            0x38
 232#define XILINX_DP_SUB_AUD_CH_B_DATA1                            0x3c
 233#define XILINX_DP_SUB_AUD_CH_B_DATA2                            0x40
 234#define XILINX_DP_SUB_AUD_CH_B_DATA3                            0x44
 235#define XILINX_DP_SUB_AUD_CH_B_DATA4                            0x48
 236#define XILINX_DP_SUB_AUD_CH_B_DATA5                            0x4c
 237#define XILINX_DP_SUB_AUD_SOFT_RESET                            0xc00
 238#define XILINX_DP_SUB_AUD_SOFT_RESET_AUD_SRST                   BIT(0)
 239
 240#define XILINX_DP_SUB_AV_BUF_NUM_VID_GFX_BUFFERS                4
 241#define XILINX_DP_SUB_AV_BUF_NUM_BUFFERS                        6
 242
 243/**
 244 * enum xilinx_drm_dp_sub_layer_type - Layer type
 245 * @XILINX_DRM_DP_SUB_LAYER_VID: video layer
 246 * @XILINX_DRM_DP_SUB_LAYER_GFX: graphics layer
 247 */
 248enum xilinx_drm_dp_sub_layer_type {
 249        XILINX_DRM_DP_SUB_LAYER_VID,
 250        XILINX_DRM_DP_SUB_LAYER_GFX
 251};
 252
 253/**
 254 * struct xilinx_drm_dp_sub_layer - DP subsystem layer
 255 * @id: layer ID
 256 * @offset: layer offset in the register space
 257 * @avail: flag if layer is available
 258 * @primary: flag for primary plane
 259 * @enabled: flag if the layer is enabled
 260 * @fmt: format descriptor
 261 * @drm_fmts: array of supported DRM formats
 262 * @num_fmts: number of supported DRM formats
 263 * @w: width
 264 * @h: height
 265 * @other: other layer
 266 */
 267struct xilinx_drm_dp_sub_layer {
 268        enum xilinx_drm_dp_sub_layer_type id;
 269        u32 offset;
 270        bool avail;
 271        bool primary;
 272        bool enabled;
 273        const struct xilinx_drm_dp_sub_fmt *fmt;
 274        uint32_t *drm_fmts;
 275        unsigned int num_fmts;
 276        uint32_t w;
 277        uint32_t h;
 278        struct xilinx_drm_dp_sub_layer *other;
 279};
 280
 281/**
 282 * struct xilinx_drm_dp_sub_blend - DP subsystem blender
 283 * @base: pre-calculated base address
 284 */
 285struct xilinx_drm_dp_sub_blend {
 286        void __iomem *base;
 287};
 288
 289/**
 290 * struct xilinx_drm_dp_sub_av_buf - DP subsystem av buffer manager
 291 * @base: pre-calculated base address
 292 */
 293struct xilinx_drm_dp_sub_av_buf {
 294        void __iomem *base;
 295};
 296
 297/**
 298 * struct xilinx_drm_dp_sub_aud - DP subsystem audio
 299 * @base: pre-calculated base address
 300 */
 301struct xilinx_drm_dp_sub_aud {
 302        void __iomem *base;
 303};
 304
 305/**
 306 * struct xilinx_drm_dp_sub - DP subsystem
 307 * @dev: device structure
 308 * @blend: blender device
 309 * @av_buf: av buffer manager device
 310 * @aud: audio device
 311 * @layers: layers
 312 * @list: entry in the global DP subsystem list
 313 * @vblank_fn: vblank handler
 314 * @vblank_data: vblank data to be used in vblank_fn
 315 * @vid_clk_pl: flag if the clock is from PL
 316 * @alpha: stored global alpha value
 317 * @alpha_en: flag if the global alpha is enabled
 318 */
 319struct xilinx_drm_dp_sub {
 320        struct device *dev;
 321        struct xilinx_drm_dp_sub_blend blend;
 322        struct xilinx_drm_dp_sub_av_buf av_buf;
 323        struct xilinx_drm_dp_sub_aud aud;
 324        struct xilinx_drm_dp_sub_layer layers[XILINX_DRM_DP_SUB_NUM_LAYERS];
 325        struct list_head list;
 326        void (*vblank_fn)(void *);
 327        void *vblank_data;
 328        bool vid_clk_pl;
 329        u32 alpha;
 330        bool alpha_en;
 331};
 332
 333/**
 334 * struct xilinx_drm_dp_sub_fmt - DP subsystem format mapping
 335 * @drm_fmt: drm format
 336 * @dp_sub_fmt: DP subsystem format
 337 * @rgb: flag for RGB formats
 338 * @swap: flag to swap r & b for rgb formats, and u & v for yuv formats
 339 * @chroma_sub: flag for chroma subsampled formats
 340 * @sf: scaling factors for upto 3 color components
 341 * @name: format name
 342 */
 343struct xilinx_drm_dp_sub_fmt {
 344        uint32_t drm_fmt;
 345        u32 dp_sub_fmt;
 346        bool rgb;
 347        bool swap;
 348        bool chroma_sub;
 349        u32 sf[3];
 350        const char *name;
 351};
 352
 353static LIST_HEAD(xilinx_drm_dp_sub_list);
 354static DEFINE_MUTEX(xilinx_drm_dp_sub_lock);
 355
 356/* Blender functions */
 357
 358/**
 359 * xilinx_drm_dp_sub_blend_layer_enable - Enable a layer
 360 * @blend: blend object
 361 * @layer: layer to enable
 362 *
 363 * Enable a layer @layer.
 364 */
 365static void
 366xilinx_drm_dp_sub_blend_layer_enable(struct xilinx_drm_dp_sub_blend *blend,
 367                                     struct xilinx_drm_dp_sub_layer *layer)
 368{
 369        u32 reg, offset, i, s0, s1;
 370        u16 sdtv_coeffs[] = { 0x1000, 0x166f, 0x0,
 371                              0x1000, 0x7483, 0x7a7f,
 372                              0x1000, 0x0, 0x1c5a };
 373        u16 swap_coeffs[] = { 0x1000, 0x0, 0x0,
 374                              0x0, 0x1000, 0x0,
 375                              0x0, 0x0, 0x1000 };
 376        u16 *coeffs;
 377        u32 offsets[] = { 0x0, 0x1800, 0x1800 };
 378
 379        reg = layer->fmt->rgb ? XILINX_DP_SUB_V_BLEND_LAYER_CONTROL_RGB : 0;
 380        reg |= layer->fmt->chroma_sub ?
 381               XILINX_DP_SUB_V_BLEND_LAYER_CONTROL_EN_US : 0;
 382
 383        xilinx_drm_writel(blend->base,
 384                          XILINX_DP_SUB_V_BLEND_LAYER_CONTROL + layer->offset,
 385                          reg);
 386
 387
 388        if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID)
 389                offset = XILINX_DP_SUB_V_BLEND_IN1CSC_COEFF0;
 390        else
 391                offset = XILINX_DP_SUB_V_BLEND_IN2CSC_COEFF0;
 392
 393        if (!layer->fmt->rgb) {
 394                coeffs = sdtv_coeffs;
 395                s0 = 1;
 396                s1 = 2;
 397        } else {
 398                coeffs = swap_coeffs;
 399                s0 = 0;
 400                s1 = 2;
 401
 402                /* No offset for RGB formats */
 403                for (i = 0; i < XILINX_DP_SUB_V_BLEND_NUM_OFFSET; i++)
 404                        offsets[i] = 0;
 405        }
 406
 407        if (layer->fmt->swap) {
 408                for (i = 0; i < 3; i++) {
 409                        coeffs[i * 3 + s0] ^= coeffs[i * 3 + s1];
 410                        coeffs[i * 3 + s1] ^= coeffs[i * 3 + s0];
 411                        coeffs[i * 3 + s0] ^= coeffs[i * 3 + s1];
 412                }
 413        }
 414
 415        /* Program coefficients. Can be runtime configurable */
 416        for (i = 0; i < XILINX_DP_SUB_V_BLEND_NUM_COEFF; i++)
 417                xilinx_drm_writel(blend->base, offset + i * 4, coeffs[i]);
 418
 419        if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID)
 420                offset = XILINX_DP_SUB_V_BLEND_LUMA_IN1CSC_OFFSET;
 421        else
 422                offset = XILINX_DP_SUB_V_BLEND_LUMA_IN2CSC_OFFSET;
 423
 424        /* Program offsets. Can be runtime configurable */
 425        for (i = 0; i < XILINX_DP_SUB_V_BLEND_NUM_OFFSET; i++)
 426                xilinx_drm_writel(blend->base, offset + i * 4, offsets[i]);
 427}
 428
 429/**
 430 * xilinx_drm_dp_sub_blend_layer_disable - Disable a layer
 431 * @blend: blend object
 432 * @layer: layer to disable
 433 *
 434 * Disable a layer @layer.
 435 */
 436static void
 437xilinx_drm_dp_sub_blend_layer_disable(struct xilinx_drm_dp_sub_blend *blend,
 438                                      struct xilinx_drm_dp_sub_layer *layer)
 439{
 440        xilinx_drm_writel(blend->base,
 441                          XILINX_DP_SUB_V_BLEND_LAYER_CONTROL + layer->offset,
 442                          0);
 443}
 444
 445/**
 446 * xilinx_drm_dp_sub_blend_set_bg_color - Set the background color
 447 * @blend: blend object
 448 * @c0: color component 0
 449 * @c1: color component 1
 450 * @c2: color component 2
 451 *
 452 * Set the background color.
 453 */
 454static void
 455xilinx_drm_dp_sub_blend_set_bg_color(struct xilinx_drm_dp_sub_blend *blend,
 456                                     u32 c0, u32 c1, u32 c2)
 457{
 458        xilinx_drm_writel(blend->base, XILINX_DP_SUB_V_BLEND_BG_CLR_0, c0);
 459        xilinx_drm_writel(blend->base, XILINX_DP_SUB_V_BLEND_BG_CLR_1, c1);
 460        xilinx_drm_writel(blend->base, XILINX_DP_SUB_V_BLEND_BG_CLR_2, c2);
 461}
 462
 463/**
 464 * xilinx_drm_dp_sub_blend_set_alpha - Set the alpha for blending
 465 * @blend: blend object
 466 * @alpha: alpha value to be used
 467 *
 468 * Set the alpha for blending.
 469 */
 470static void
 471xilinx_drm_dp_sub_blend_set_alpha(struct xilinx_drm_dp_sub_blend *blend,
 472                                  u32 alpha)
 473{
 474        u32 reg;
 475
 476        reg = xilinx_drm_readl(blend->base,
 477                               XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA);
 478        reg &= ~XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA_MASK;
 479        reg |= alpha << 1;
 480        xilinx_drm_writel(blend->base, XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA,
 481                          reg);
 482}
 483
 484/**
 485 * xilinx_drm_dp_sub_blend_enable_alpha - Enable/disable the global alpha
 486 * @blend: blend object
 487 * @enable: flag to enable or disable alpha blending
 488 *
 489 * Enable/disable the global alpha blending based on @enable.
 490 */
 491static void
 492xilinx_drm_dp_sub_blend_enable_alpha(struct xilinx_drm_dp_sub_blend *blend,
 493                                     bool enable)
 494{
 495        if (enable)
 496                xilinx_drm_set(blend->base,
 497                               XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA, BIT(0));
 498        else
 499                xilinx_drm_clr(blend->base,
 500                               XILINX_DP_SUB_V_BLEND_SET_GLOBAL_ALPHA, BIT(0));
 501}
 502
 503static const struct xilinx_drm_dp_sub_fmt blend_output_fmts[] = {
 504        {
 505                .drm_fmt        = DRM_FORMAT_RGB888,
 506                .dp_sub_fmt     = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_RGB,
 507                .rgb            = true,
 508                .swap           = false,
 509                .chroma_sub     = false,
 510                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 511                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 512                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 513                .name           = "rgb888",
 514        }, {
 515                .drm_fmt        = DRM_FORMAT_YUV444,
 516                .dp_sub_fmt     = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YCBCR444,
 517                .rgb            = false,
 518                .swap           = false,
 519                .chroma_sub     = false,
 520                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 521                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 522                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 523                .name           = "yuv444",
 524        }, {
 525                .drm_fmt        = DRM_FORMAT_YUV422,
 526                .dp_sub_fmt     = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YCBCR422,
 527                .rgb            = false,
 528                .swap           = false,
 529                .chroma_sub     = true,
 530                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 531                .sf[1]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 532                .sf[2]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 533                .name           = "yuv422",
 534        }, {
 535        }
 536};
 537
 538/**
 539 * xilinx_drm_dp_sub_blend_set_output_fmt - Set the output format
 540 * @blend: blend object
 541 * @fmt: output format
 542 *
 543 * Set the output format to @fmt.
 544 */
 545static void
 546xilinx_drm_dp_sub_blend_set_output_fmt(struct xilinx_drm_dp_sub_blend *blend,
 547                                       u32 fmt)
 548{
 549        xilinx_drm_writel(blend->base, XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT,
 550                          fmt);
 551}
 552
 553/* AV buffer manager functions */
 554
 555static const struct xilinx_drm_dp_sub_fmt av_buf_vid_fmts[] = {
 556        {
 557                .drm_fmt        = DRM_FORMAT_VYUY,
 558                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_VYUY,
 559                .rgb            = false,
 560                .swap           = true,
 561                .chroma_sub     = true,
 562                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 563                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 564                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 565                .name           = "vyuy",
 566        }, {
 567                .drm_fmt        = DRM_FORMAT_UYVY,
 568                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_VYUY,
 569                .rgb            = false,
 570                .swap           = false,
 571                .chroma_sub     = true,
 572                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 573                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 574                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 575                .name           = "uyvy",
 576        }, {
 577                .drm_fmt        = DRM_FORMAT_YUYV,
 578                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YUYV,
 579                .rgb            = false,
 580                .swap           = false,
 581                .chroma_sub     = true,
 582                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 583                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 584                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 585                .name           = "yuyv",
 586        }, {
 587                .drm_fmt        = DRM_FORMAT_YVYU,
 588                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YUYV,
 589                .rgb            = false,
 590                .swap           = true,
 591                .chroma_sub     = true,
 592                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 593                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 594                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 595                .name           = "yvyu",
 596        }, {
 597                .drm_fmt        = DRM_FORMAT_NV16,
 598                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI,
 599                .rgb            = false,
 600                .swap           = false,
 601                .chroma_sub     = true,
 602                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 603                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 604                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 605                .name           = "nv16",
 606        }, {
 607                .drm_fmt        = DRM_FORMAT_NV61,
 608                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI,
 609                .rgb            = false,
 610                .swap           = true,
 611                .chroma_sub     = true,
 612                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 613                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 614                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 615                .name           = "nv61",
 616        }, {
 617                .drm_fmt        = DRM_FORMAT_BGR888,
 618                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGB888,
 619                .rgb            = true,
 620                .swap           = false,
 621                .chroma_sub     = false,
 622                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 623                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 624                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 625                .name           = "bgr888",
 626        }, {
 627                .drm_fmt        = DRM_FORMAT_RGB888,
 628                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGB888,
 629                .rgb            = true,
 630                .swap           = true,
 631                .chroma_sub     = false,
 632                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 633                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 634                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 635                .name           = "rgb888",
 636        }, {
 637                .drm_fmt        = DRM_FORMAT_XBGR8888,
 638                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGBA8880,
 639                .rgb            = true,
 640                .swap           = false,
 641                .chroma_sub     = false,
 642                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 643                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 644                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 645                .name           = "xbgr8888",
 646        }, {
 647                .drm_fmt        = DRM_FORMAT_XRGB8888,
 648                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_RGBA8880,
 649                .rgb            = true,
 650                .swap           = true,
 651                .chroma_sub     = false,
 652                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 653                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 654                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 655                .name           = "xrgb8888",
 656        }, {
 657                .drm_fmt        = DRM_FORMAT_NV12,
 658                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI_420,
 659                .rgb            = false,
 660                .swap           = false,
 661                .chroma_sub     = true,
 662                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 663                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 664                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 665                .name           = "nv12",
 666        }, {
 667                .drm_fmt        = DRM_FORMAT_NV21,
 668                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_VID_YV16CI_420,
 669                .rgb            = false,
 670                .swap           = true,
 671                .chroma_sub     = true,
 672                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 673                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 674                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 675                .name           = "nv21",
 676        }
 677};
 678
 679static const struct xilinx_drm_dp_sub_fmt av_buf_gfx_fmts[] = {
 680        {
 681                .drm_fmt        = DRM_FORMAT_ABGR8888,
 682                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA8888,
 683                .rgb            = true,
 684                .swap           = false,
 685                .chroma_sub     = false,
 686                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 687                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 688                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 689                .name           = "abgr8888",
 690        }, {
 691                .drm_fmt        = DRM_FORMAT_ARGB8888,
 692                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA8888,
 693                .rgb            = true,
 694                .swap           = true,
 695                .chroma_sub     = false,
 696                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 697                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 698                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 699                .name           = "argb8888",
 700        }, {
 701                .drm_fmt        = DRM_FORMAT_RGBA8888,
 702                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_ABGR8888,
 703                .rgb            = true,
 704                .swap           = false,
 705                .chroma_sub     = false,
 706                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 707                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 708                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 709                .name           = "rgba8888",
 710        }, {
 711                .drm_fmt        = DRM_FORMAT_BGRA8888,
 712                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_ABGR8888,
 713                .rgb            = true,
 714                .swap           = true,
 715                .chroma_sub     = false,
 716                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 717                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 718                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 719                .name           = "bgra8888",
 720        }, {
 721                .drm_fmt        = DRM_FORMAT_BGR888,
 722                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGB888,
 723                .rgb            = true,
 724                .swap           = false,
 725                .chroma_sub     = false,
 726                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 727                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 728                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 729                .name           = "bgr888",
 730        }, {
 731                .drm_fmt        = DRM_FORMAT_RGB888,
 732                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_BGR888,
 733                .rgb            = true,
 734                .swap           = false,
 735                .chroma_sub     = false,
 736                .sf[0]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 737                .sf[1]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 738                .sf[2]          = XILINX_DP_SUB_AV_BUF_8BIT_SF,
 739                .name           = "rgb888",
 740        }, {
 741                .drm_fmt        = DRM_FORMAT_RGBA5551,
 742                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA5551,
 743                .rgb            = true,
 744                .swap           = false,
 745                .chroma_sub     = false,
 746                .sf[0]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 747                .sf[1]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 748                .sf[2]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 749                .name           = "rgba5551",
 750        }, {
 751                .drm_fmt        = DRM_FORMAT_BGRA5551,
 752                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA5551,
 753                .rgb            = true,
 754                .swap           = true,
 755                .chroma_sub     = false,
 756                .sf[0]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 757                .sf[1]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 758                .sf[2]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 759                .name           = "bgra5551",
 760        }, {
 761                .drm_fmt        = DRM_FORMAT_RGBA4444,
 762                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA4444,
 763                .rgb            = true,
 764                .swap           = false,
 765                .chroma_sub     = false,
 766                .sf[0]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 767                .sf[1]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 768                .sf[2]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 769                .name           = "rgba4444",
 770        }, {
 771                .drm_fmt        = DRM_FORMAT_BGRA4444,
 772                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGBA4444,
 773                .rgb            = true,
 774                .swap           = true,
 775                .chroma_sub     = false,
 776                .sf[0]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 777                .sf[1]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 778                .sf[2]          = XILINX_DP_SUB_AV_BUF_4BIT_SF,
 779                .name           = "bgra4444",
 780        }, {
 781                .drm_fmt        = DRM_FORMAT_RGB565,
 782                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGB565,
 783                .rgb            = true,
 784                .swap           = false,
 785                .chroma_sub     = false,
 786                .sf[0]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 787                .sf[1]          = XILINX_DP_SUB_AV_BUF_6BIT_SF,
 788                .sf[2]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 789                .name           = "rgb565",
 790        }, {
 791                .drm_fmt        = DRM_FORMAT_BGR565,
 792                .dp_sub_fmt     = XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_RGB565,
 793                .rgb            = true,
 794                .swap           = true,
 795                .chroma_sub     = false,
 796                .sf[0]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 797                .sf[1]          = XILINX_DP_SUB_AV_BUF_6BIT_SF,
 798                .sf[2]          = XILINX_DP_SUB_AV_BUF_5BIT_SF,
 799                .name           = "bgr565",
 800        }
 801};
 802
 803/**
 804 * xilinx_drm_dp_sub_av_buf_set_fmt - Set the input formats
 805 * @av_buf: av buffer manager
 806 * @fmt: formats
 807 *
 808 * Set the av buffer manager format to @fmt. @fmt should have valid values
 809 * for both video and graphics layer.
 810 */
 811static void
 812xilinx_drm_dp_sub_av_buf_set_fmt(struct xilinx_drm_dp_sub_av_buf *av_buf,
 813                                 u32 fmt)
 814{
 815        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_FMT, fmt);
 816}
 817
 818/**
 819 * xilinx_drm_dp_sub_av_buf_get_fmt - Get the input formats
 820 * @av_buf: av buffer manager
 821 *
 822 * Get the input formats (which include video and graphics) of
 823 * av buffer manager.
 824 *
 825 * Return: value of XILINX_DP_SUB_AV_BUF_FMT register.
 826 */
 827static u32
 828xilinx_drm_dp_sub_av_buf_get_fmt(struct xilinx_drm_dp_sub_av_buf *av_buf)
 829{
 830        return xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_FMT);
 831}
 832
 833/**
 834 * xilinx_drm_dp_sub_av_buf_set_vid_clock_src - Set the video clock source
 835 * @av_buf: av buffer manager
 836 * @from_ps: flag if the video clock is from ps
 837 *
 838 * Set the video clock source based on @from_ps. It can come from either PS or
 839 * PL.
 840 */
 841static void xilinx_drm_dp_sub_av_buf_set_vid_clock_src(
 842                struct xilinx_drm_dp_sub_av_buf *av_buf, bool from_ps)
 843{
 844        u32 reg;
 845
 846        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_CLK_SRC);
 847        if (from_ps)
 848                reg |= XILINX_DP_SUB_AV_BUF_CLK_SRC_VID_FROM_PS;
 849        else
 850                reg &= ~XILINX_DP_SUB_AV_BUF_CLK_SRC_VID_FROM_PS;
 851        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_CLK_SRC, reg);
 852}
 853
 854/**
 855 * xilinx_drm_dp_sub_av_buf_set_vid_timing_src - Set the video timing source
 856 * @av_buf: av buffer manager
 857 * @internal: flag if the video timing is generated internally
 858 *
 859 * Set the video timing source based on @internal. It can come externally or
 860 * be generated internally.
 861 */
 862static void xilinx_drm_dp_sub_av_buf_set_vid_timing_src(
 863                struct xilinx_drm_dp_sub_av_buf *av_buf, bool internal)
 864{
 865        u32 reg;
 866
 867        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_CLK_SRC);
 868        if (internal)
 869                reg |= XILINX_DP_SUB_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING;
 870        else
 871                reg &= ~XILINX_DP_SUB_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING;
 872        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_CLK_SRC, reg);
 873}
 874
 875/**
 876 * xilinx_drm_dp_sub_av_buf_set_aud_clock_src - Set the audio clock source
 877 * @av_buf: av buffer manager
 878 * @from_ps: flag if the video clock is from ps
 879 *
 880 * Set the audio clock source based on @from_ps. It can come from either PS or
 881 * PL.
 882 */
 883static void xilinx_drm_dp_sub_av_buf_set_aud_clock_src(
 884                struct xilinx_drm_dp_sub_av_buf *av_buf, bool from_ps)
 885{
 886        u32 reg;
 887
 888        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_CLK_SRC);
 889        if (from_ps)
 890                reg |= XILINX_DP_SUB_AV_BUF_CLK_SRC_AUD_FROM_PS;
 891        else
 892                reg &= ~XILINX_DP_SUB_AV_BUF_CLK_SRC_AUD_FROM_PS;
 893        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_CLK_SRC, reg);
 894}
 895
 896/**
 897 * xilinx_drm_dp_sub_av_buf_enable_buf - Enable buffers
 898 * @av_buf: av buffer manager
 899 *
 900 * Enable all (video and audio) buffers.
 901 */
 902static void
 903xilinx_drm_dp_sub_av_buf_enable_buf(struct xilinx_drm_dp_sub_av_buf *av_buf)
 904{
 905        u32 reg, i;
 906
 907        reg = XILINX_DP_SUB_AV_BUF_CHBUF_EN;
 908        reg |= XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_MAX <<
 909               XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_SHIFT;
 910
 911        for (i = 0; i < XILINX_DP_SUB_AV_BUF_NUM_VID_GFX_BUFFERS; i++)
 912                xilinx_drm_writel(av_buf->base,
 913                                  XILINX_DP_SUB_AV_BUF_CHBUF + i * 4, reg);
 914
 915        reg = XILINX_DP_SUB_AV_BUF_CHBUF_EN;
 916        reg |= XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_AUD_MAX <<
 917               XILINX_DP_SUB_AV_BUF_CHBUF_BURST_LEN_SHIFT;
 918
 919        for (; i < XILINX_DP_SUB_AV_BUF_NUM_BUFFERS; i++)
 920                xilinx_drm_writel(av_buf->base,
 921                                  XILINX_DP_SUB_AV_BUF_CHBUF + i * 4, reg);
 922}
 923
 924/**
 925 * xilinx_drm_dp_sub_av_buf_disable_buf - Disable buffers
 926 * @av_buf: av buffer manager
 927 *
 928 * Disable all (video and audio) buffers.
 929 */
 930static void
 931xilinx_drm_dp_sub_av_buf_disable_buf(struct xilinx_drm_dp_sub_av_buf *av_buf)
 932{
 933        u32 reg, i;
 934
 935        reg = XILINX_DP_SUB_AV_BUF_CHBUF_FLUSH & ~XILINX_DP_SUB_AV_BUF_CHBUF_EN;
 936        for (i = 0; i < XILINX_DP_SUB_AV_BUF_NUM_BUFFERS; i++)
 937                xilinx_drm_writel(av_buf->base,
 938                                  XILINX_DP_SUB_AV_BUF_CHBUF + i * 4, reg);
 939}
 940
 941/**
 942 * xilinx_drm_dp_sub_av_buf_enable_aud - Enable audio
 943 * @av_buf: av buffer manager
 944 *
 945 * Enable all audio buffers.
 946 */
 947static void
 948xilinx_drm_dp_sub_av_buf_enable_aud(struct xilinx_drm_dp_sub_av_buf *av_buf)
 949{
 950        u32 reg;
 951
 952        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT);
 953        reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_MASK;
 954        reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_MEM;
 955        reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_AUD2_EN;
 956        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT, reg);
 957}
 958
 959/**
 960 * xilinx_drm_dp_sub_av_buf_enable - Enable the video pipe
 961 * @av_buf: av buffer manager
 962 *
 963 * De-assert the video pipe reset
 964 */
 965static void
 966xilinx_drm_dp_sub_av_buf_enable(struct xilinx_drm_dp_sub_av_buf *av_buf)
 967{
 968        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_SRST_REG, 0);
 969}
 970
 971/**
 972 * xilinx_drm_dp_sub_av_buf_disable - Disable the video pipe
 973 * @av_buf: av buffer manager
 974 *
 975 * Assert the video pipe reset
 976 */
 977static void
 978xilinx_drm_dp_sub_av_buf_disable(struct xilinx_drm_dp_sub_av_buf *av_buf)
 979{
 980        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_SRST_REG,
 981                          XILINX_DP_SUB_AV_BUF_SRST_REG_VID_RST);
 982}
 983
 984/**
 985 * xilinx_drm_dp_sub_av_buf_disable_aud - Disable audio
 986 * @av_buf: av buffer manager
 987 *
 988 * Disable all audio buffers.
 989 */
 990static void
 991xilinx_drm_dp_sub_av_buf_disable_aud(struct xilinx_drm_dp_sub_av_buf *av_buf)
 992{
 993        u32 reg;
 994
 995        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT);
 996        reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_MASK;
 997        reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_AUD1_DISABLE;
 998        reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_AUD2_EN;
 999        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT, reg);
1000}
1001
1002/**
1003 * xilinx_drm_dp_sub_av_buf_enable_vid - Enable the video layer buffer
1004 * @av_buf: av buffer manager
1005 * @layer: layer to enable
1006 *
1007 * Enable the video/graphics buffer for @layer.
1008 */
1009static void
1010xilinx_drm_dp_sub_av_buf_enable_vid(struct xilinx_drm_dp_sub_av_buf *av_buf,
1011                                    struct xilinx_drm_dp_sub_layer *layer)
1012{
1013        u32 reg;
1014
1015        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT);
1016        if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID) {
1017                reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_MASK;
1018                reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_MEM;
1019        } else {
1020                reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_MASK;
1021                reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_MEM;
1022        }
1023        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT, reg);
1024}
1025
1026/**
1027 * xilinx_drm_dp_sub_av_buf_disable_vid - Disable the video layer buffer
1028 * @av_buf: av buffer manager
1029 * @layer: layer to disable
1030 *
1031 * Disable the video/graphics buffer for @layer.
1032 */
1033static void
1034xilinx_drm_dp_sub_av_buf_disable_vid(struct xilinx_drm_dp_sub_av_buf *av_buf,
1035                                     struct xilinx_drm_dp_sub_layer *layer)
1036{
1037        u32 reg;
1038
1039        reg = xilinx_drm_readl(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT);
1040
1041        if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID) {
1042                reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_MASK;
1043                reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_VID1_NONE;
1044        } else {
1045                reg &= ~XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_MASK;
1046                reg |= XILINX_DP_SUB_AV_BUF_OUTPUT_VID2_DISABLE;
1047        }
1048
1049        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_OUTPUT, reg);
1050}
1051
1052/**
1053 * xilinx_drm_dp_sub_av_buf_init_fmts - Initialize the layer formats
1054 * @av_buf: av buffer manager
1055 * @vid_fmt: video format descriptor
1056 * @gfx_fmt: graphics format descriptor
1057 *
1058 * Initialize formats of both video and graphics layers.
1059 */
1060static void
1061xilinx_drm_dp_sub_av_buf_init_fmts(struct xilinx_drm_dp_sub_av_buf *av_buf,
1062                                   const struct xilinx_drm_dp_sub_fmt *vid_fmt,
1063                                   const struct xilinx_drm_dp_sub_fmt *gfx_fmt)
1064{
1065        u32 reg;
1066
1067        reg = vid_fmt->dp_sub_fmt;
1068        reg |= gfx_fmt->dp_sub_fmt;
1069        xilinx_drm_writel(av_buf->base, XILINX_DP_SUB_AV_BUF_FMT, reg);
1070}
1071
1072/**
1073 * xilinx_drm_dp_sub_av_buf_init_sf - Initialize scaling factors
1074 * @av_buf: av buffer manager
1075 * @vid_fmt: video format descriptor
1076 * @gfx_fmt: graphics format descriptor
1077 *
1078 * Initialize scaling factors for both video and graphics layers.
1079 */
1080static void
1081xilinx_drm_dp_sub_av_buf_init_sf(struct xilinx_drm_dp_sub_av_buf *av_buf,
1082                                 const struct xilinx_drm_dp_sub_fmt *vid_fmt,
1083                                 const struct xilinx_drm_dp_sub_fmt *gfx_fmt)
1084{
1085        unsigned int i;
1086        int offset;
1087
1088        offset = XILINX_DP_SUB_AV_BUF_GFX_COMP0_SF;
1089        for (i = 0; i < XILINX_DP_SUB_AV_BUF_NUM_SF; i++)
1090                xilinx_drm_writel(av_buf->base, offset + i * 4, gfx_fmt->sf[i]);
1091
1092        offset = XILINX_DP_SUB_AV_BUF_VID_COMP0_SF;
1093        for (i = 0; i < XILINX_DP_SUB_AV_BUF_NUM_SF; i++)
1094                xilinx_drm_writel(av_buf->base, offset + i * 4, vid_fmt->sf[i]);
1095}
1096
1097/* Audio functions */
1098
1099/**
1100 * xilinx_drm_dp_sub_aud_init - Initialize the audio
1101 * @aud: audio
1102 *
1103 * Initialize the audio with default mixer volume. The de-assertion will
1104 * initialize the audio states.
1105 */
1106static void xilinx_drm_dp_sub_aud_init(struct xilinx_drm_dp_sub_aud *aud)
1107{
1108        /* Clear the audio soft reset register as it's an non-reset flop */
1109        xilinx_drm_writel(aud->base, XILINX_DP_SUB_AUD_SOFT_RESET, 0);
1110        xilinx_drm_writel(aud->base, XILINX_DP_SUB_AUD_MIXER_VOLUME,
1111                          XILINX_DP_SUB_AUD_MIXER_VOLUME_NO_SCALE);
1112}
1113
1114/**
1115 * xilinx_drm_dp_sub_aud_deinit - De-initialize the audio
1116 * @aud: audio
1117 *
1118 * Put the audio in reset.
1119 */
1120static void xilinx_drm_dp_sub_aud_deinit(struct xilinx_drm_dp_sub_aud *aud)
1121{
1122        xilinx_drm_set(aud->base, XILINX_DP_SUB_AUD_SOFT_RESET,
1123                       XILINX_DP_SUB_AUD_SOFT_RESET_AUD_SRST);
1124}
1125
1126/* DP subsystem layer functions */
1127
1128/**
1129 * xilinx_drm_dp_sub_layer_check_size - Verify width and height for the layer
1130 * @dp_sub: DP subsystem
1131 * @layer: layer
1132 * @width: width
1133 * @height: height
1134 *
1135 * The DP subsystem has the limitation that both layers should have
1136 * identical size. This function stores width and height of @layer, and verifies
1137 * if the size (width and height) is valid.
1138 *
1139 * Return: 0 on success, or -EINVAL if width or/and height is invalid.
1140 */
1141int xilinx_drm_dp_sub_layer_check_size(struct xilinx_drm_dp_sub *dp_sub,
1142                                       struct xilinx_drm_dp_sub_layer *layer,
1143                                       uint32_t width, uint32_t height)
1144{
1145        struct xilinx_drm_dp_sub_layer *other = layer->other;
1146
1147        if (other->enabled && (other->w != width || other->h != height)) {
1148                dev_err(dp_sub->dev, "Layer width:height must be %d:%d\n",
1149                        other->w, other->h);
1150                return -EINVAL;
1151        }
1152
1153        layer->w = width;
1154        layer->h = height;
1155
1156        return 0;
1157}
1158EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_check_size);
1159
1160/**
1161 * xilinx_drm_dp_sub_map_fmt - Find the DP subsystem format for given drm format
1162 * @fmts: format table to look up
1163 * @size: size of the table @fmts
1164 * @drm_fmt: DRM format to search
1165 *
1166 * Search a DP subsystem format corresponding to the given DRM format @drm_fmt,
1167 * and return the format descriptor which contains the DP subsystem format
1168 * value.
1169 *
1170 * Return: a DP subsystem format descriptor on success, or NULL.
1171 */
1172static const struct xilinx_drm_dp_sub_fmt *
1173xilinx_drm_dp_sub_map_fmt(const struct xilinx_drm_dp_sub_fmt fmts[],
1174                          unsigned int size, uint32_t drm_fmt)
1175{
1176        unsigned int i;
1177
1178        for (i = 0; i < size; i++)
1179                if (fmts[i].drm_fmt == drm_fmt)
1180                        return &fmts[i];
1181
1182        return NULL;
1183}
1184
1185/**
1186 * xilinx_drm_dp_sub_set_fmt - Set the format of the layer
1187 * @dp_sub: DP subsystem
1188 * @layer: layer to set the format
1189 * @drm_fmt: DRM format to set
1190 *
1191 * Set the format of the given layer to @drm_fmt.
1192 *
1193 * Return: 0 on success. -EINVAL if @drm_fmt is not supported by the layer.
1194 */
1195int xilinx_drm_dp_sub_layer_set_fmt(struct xilinx_drm_dp_sub *dp_sub,
1196                                    struct xilinx_drm_dp_sub_layer *layer,
1197                                    uint32_t drm_fmt)
1198{
1199        const struct xilinx_drm_dp_sub_fmt *table;
1200        const struct xilinx_drm_dp_sub_fmt *fmt;
1201        u32 size, fmts, mask;
1202
1203        if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID) {
1204                table = av_buf_vid_fmts;
1205                size = ARRAY_SIZE(av_buf_vid_fmts);
1206                mask = ~XILINX_DP_SUB_AV_BUF_FMT_NL_VID_MASK;
1207        } else {
1208                table = av_buf_gfx_fmts;
1209                size = ARRAY_SIZE(av_buf_gfx_fmts);
1210                mask = ~XILINX_DP_SUB_AV_BUF_FMT_NL_GFX_MASK;
1211        }
1212
1213        fmt = xilinx_drm_dp_sub_map_fmt(table, size, drm_fmt);
1214        if (!fmt)
1215                return -EINVAL;
1216
1217        fmts = xilinx_drm_dp_sub_av_buf_get_fmt(&dp_sub->av_buf);
1218        fmts &= mask;
1219        fmts |= fmt->dp_sub_fmt;
1220        xilinx_drm_dp_sub_av_buf_set_fmt(&dp_sub->av_buf, fmts);
1221
1222        layer->fmt = fmt;
1223
1224        return 0;
1225}
1226EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_set_fmt);
1227
1228/**
1229 * xilinx_drm_dp_sub_get_fmt - Get the format of the layer
1230 * @dp_sub: DP subsystem
1231 * @layer: layer to set the format
1232 *
1233 * Get the format of the given layer.
1234 *
1235 * Return: DRM format of the layer
1236 */
1237uint32_t xilinx_drm_dp_sub_layer_get_fmt(struct xilinx_drm_dp_sub *dp_sub,
1238                                         struct xilinx_drm_dp_sub_layer *layer)
1239{
1240        return layer->fmt->drm_fmt;
1241}
1242EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_get_fmt);
1243
1244/**
1245 * xilinx_drm_dp_sub_get_fmt - Get the supported DRM formats of the layer
1246 * @dp_sub: DP subsystem
1247 * @layer: layer to get the formats
1248 * @drm_fmts: pointer to array of DRM format strings
1249 * @num_fmts: pointer to number of returned DRM formats
1250 *
1251 * Get the supported DRM formats of the given layer.
1252 */
1253void xilinx_drm_dp_sub_layer_get_fmts(struct xilinx_drm_dp_sub *dp_sub,
1254                                      struct xilinx_drm_dp_sub_layer *layer,
1255                                      uint32_t **drm_fmts,
1256                                      unsigned int *num_fmts)
1257{
1258        *drm_fmts = layer->drm_fmts;
1259        *num_fmts = layer->num_fmts;
1260}
1261EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_get_fmts);
1262
1263/**
1264 * xilinx_drm_dp_sub_layer_enable - Enable the layer
1265 * @dp_sub: DP subsystem
1266 * @layer: layer to esable
1267 *
1268 * Enable the layer @layer.
1269 */
1270void xilinx_drm_dp_sub_layer_enable(struct xilinx_drm_dp_sub *dp_sub,
1271                                    struct xilinx_drm_dp_sub_layer *layer)
1272{
1273        xilinx_drm_dp_sub_av_buf_enable_vid(&dp_sub->av_buf, layer);
1274        xilinx_drm_dp_sub_blend_layer_enable(&dp_sub->blend, layer);
1275        layer->enabled = true;
1276        if (layer->other->enabled) {
1277                xilinx_drm_dp_sub_blend_set_alpha(&dp_sub->blend,
1278                                                  dp_sub->alpha);
1279                xilinx_drm_dp_sub_blend_enable_alpha(&dp_sub->blend,
1280                                                     dp_sub->alpha_en);
1281        } else {
1282                u32 alpha;
1283
1284                if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID)
1285                        alpha = 0;
1286                else
1287                        alpha = XILINX_DRM_DP_SUB_MAX_ALPHA;
1288                xilinx_drm_dp_sub_blend_set_alpha(&dp_sub->blend, alpha);
1289                xilinx_drm_dp_sub_blend_enable_alpha(&dp_sub->blend, true);
1290        }
1291}
1292EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_enable);
1293
1294/**
1295 * xilinx_drm_dp_sub_layer_enable - Disable the layer
1296 * @dp_sub: DP subsystem
1297 * @layer: layer to disable
1298 *
1299 * Disable the layer @layer.
1300 */
1301void xilinx_drm_dp_sub_layer_disable(struct xilinx_drm_dp_sub *dp_sub,
1302                                     struct xilinx_drm_dp_sub_layer *layer)
1303{
1304        xilinx_drm_dp_sub_av_buf_disable_vid(&dp_sub->av_buf, layer);
1305        xilinx_drm_dp_sub_blend_layer_disable(&dp_sub->blend, layer);
1306        layer->enabled = false;
1307        if (layer->other->enabled) {
1308                u32 alpha;
1309
1310                if (layer->id == XILINX_DRM_DP_SUB_LAYER_VID)
1311                        alpha = XILINX_DRM_DP_SUB_MAX_ALPHA;
1312                else
1313                        alpha = 0;
1314                xilinx_drm_dp_sub_blend_set_alpha(&dp_sub->blend, alpha);
1315                xilinx_drm_dp_sub_blend_enable_alpha(&dp_sub->blend, true);
1316        }
1317}
1318EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_disable);
1319
1320/**
1321 * xilinx_drm_dp_sub_layer_get - Get the DP subsystem layer
1322 * @dp_sub: DP subsystem
1323 * @primary: flag to indicate the primary plane
1324 *
1325 * Check if there's any available layer based on the flag @primary, and return
1326 * the found layer.
1327 *
1328 * Return: a DP subsystem layer on success, or -ENODEV error pointer.
1329 */
1330struct xilinx_drm_dp_sub_layer *
1331xilinx_drm_dp_sub_layer_get(struct xilinx_drm_dp_sub *dp_sub, bool primary)
1332{
1333        struct xilinx_drm_dp_sub_layer *layer = NULL;
1334        unsigned int i;
1335
1336        for (i = 0; i < XILINX_DRM_DP_SUB_NUM_LAYERS; i++) {
1337                if (dp_sub->layers[i].primary == primary) {
1338                        layer = &dp_sub->layers[i];
1339                        break;
1340                }
1341        }
1342
1343        if (!layer || !layer->avail)
1344                return ERR_PTR(-ENODEV);
1345
1346        return layer;
1347
1348}
1349EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_get);
1350
1351/**
1352 * xilinx_drm_dp_sub_layer_get - Put the DP subsystem layer
1353 * @dp_sub: DP subsystem
1354 * @layer: DP subsystem layer
1355 *
1356 * Return the DP subsystem layer @layer when it's no longer used.
1357 */
1358void xilinx_drm_dp_sub_layer_put(struct xilinx_drm_dp_sub *dp_sub,
1359                                 struct xilinx_drm_dp_sub_layer *layer)
1360{
1361        layer->avail = true;
1362}
1363EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_layer_put);
1364
1365/* DP subsystem functions */
1366
1367/**
1368 * xilinx_drm_dp_sub_set_output_fmt - Set the output format
1369 * @dp_sub: DP subsystem
1370 * @drm_fmt: DRM format to set
1371 *
1372 * Set the output format of the DP subsystem. The flag @primary indicates that
1373 * which layer to configure.
1374 *
1375 * Return: 0 on success, or -EINVAL if @drm_fmt is not supported for output.
1376 */
1377int xilinx_drm_dp_sub_set_output_fmt(struct xilinx_drm_dp_sub *dp_sub,
1378                                     uint32_t drm_fmt)
1379{
1380        const struct xilinx_drm_dp_sub_fmt *fmt;
1381
1382        fmt = xilinx_drm_dp_sub_map_fmt(blend_output_fmts,
1383                                        ARRAY_SIZE(blend_output_fmts), drm_fmt);
1384        if (!fmt)
1385                return -EINVAL;
1386
1387        xilinx_drm_dp_sub_blend_set_output_fmt(&dp_sub->blend, fmt->dp_sub_fmt);
1388
1389        return 0;
1390}
1391EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_set_output_fmt);
1392
1393/**
1394 * xilinx_drm_dp_sub_set_bg_color - Set the background color
1395 * @dp_sub: DP subsystem
1396 * @c0: color component 0
1397 * @c1: color component 1
1398 * @c2: color component 2
1399 *
1400 * Set the background color with given color components (@c0, @c1, @c2).
1401 */
1402void xilinx_drm_dp_sub_set_bg_color(struct xilinx_drm_dp_sub *dp_sub,
1403                                    u32 c0, u32 c1, u32 c2)
1404{
1405        xilinx_drm_dp_sub_blend_set_bg_color(&dp_sub->blend, c0, c1, c2);
1406}
1407EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_set_bg_color);
1408
1409/**
1410 * xilinx_drm_dp_sub_set_alpha - Set the alpha value
1411 * @dp_sub: DP subsystem
1412 * @alpha: alpha value to set
1413 *
1414 * Set the alpha value for blending.
1415 */
1416void xilinx_drm_dp_sub_set_alpha(struct xilinx_drm_dp_sub *dp_sub, u32 alpha)
1417{
1418        dp_sub->alpha = alpha;
1419        if (dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_VID].enabled &&
1420            dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_GFX].enabled)
1421                xilinx_drm_dp_sub_blend_set_alpha(&dp_sub->blend, alpha);
1422}
1423EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_set_alpha);
1424
1425/**
1426 * xilinx_drm_dp_sub_enable_alpha - Enable/disable the global alpha blending
1427 * @dp_sub: DP subsystem
1428 * @enable: flag to enable or disable alpha blending
1429 *
1430 * Set the alpha value for blending.
1431 */
1432void
1433xilinx_drm_dp_sub_enable_alpha(struct xilinx_drm_dp_sub *dp_sub, bool enable)
1434{
1435        dp_sub->alpha_en = enable;
1436        if (dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_VID].enabled &&
1437            dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_GFX].enabled)
1438                xilinx_drm_dp_sub_blend_enable_alpha(&dp_sub->blend, enable);
1439}
1440EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_enable_alpha);
1441
1442/**
1443 * xilinx_drm_dp_sub_handle_vblank - Vblank handling wrapper
1444 * @dp_sub: DP subsystem
1445 *
1446 * Trigger the registered vblank handler. This function is supposed to be
1447 * called in the actual vblank handler.
1448 */
1449void xilinx_drm_dp_sub_handle_vblank(struct xilinx_drm_dp_sub *dp_sub)
1450{
1451        if (dp_sub->vblank_fn)
1452                dp_sub->vblank_fn(dp_sub->vblank_data);
1453}
1454EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_handle_vblank);
1455
1456/**
1457 * xilinx_drm_dp_sub_enable_vblank - Enable the vblank handling
1458 * @dp_sub: DP subsystem
1459 * @vblank_fn: callback to be called on vblank event
1460 * @vblank_data: data to be used in @vblank_fn
1461 *
1462 * This function register the vblank handler, and the handler will be triggered
1463 * on vblank event after.
1464 */
1465void xilinx_drm_dp_sub_enable_vblank(struct xilinx_drm_dp_sub *dp_sub,
1466                                     void (*vblank_fn)(void *),
1467                                     void *vblank_data)
1468{
1469        dp_sub->vblank_fn = vblank_fn;
1470        dp_sub->vblank_data = vblank_data;
1471}
1472EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_enable_vblank);
1473
1474/**
1475 * xilinx_drm_dp_sub_disable_vblank - Disable the vblank handling
1476 * @dp_sub: DP subsystem
1477 *
1478 * Disable the vblank handler. The vblank handler and data are unregistered.
1479 */
1480void xilinx_drm_dp_sub_disable_vblank(struct xilinx_drm_dp_sub *dp_sub)
1481{
1482        dp_sub->vblank_fn = NULL;
1483        dp_sub->vblank_data = NULL;
1484}
1485EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_disable_vblank);
1486
1487/**
1488 * xilinx_drm_dp_sub_enable - Enable the DP subsystem
1489 * @dp_sub: DP subsystem
1490 *
1491 * Enable the DP subsystem.
1492 */
1493void xilinx_drm_dp_sub_enable(struct xilinx_drm_dp_sub *dp_sub)
1494{
1495        const struct xilinx_drm_dp_sub_fmt *vid_fmt;
1496        const struct xilinx_drm_dp_sub_fmt *gfx_fmt;
1497
1498        vid_fmt = dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_VID].fmt;
1499        gfx_fmt = dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_GFX].fmt;
1500        xilinx_drm_dp_sub_av_buf_enable(&dp_sub->av_buf);
1501        xilinx_drm_dp_sub_av_buf_init_fmts(&dp_sub->av_buf, vid_fmt, gfx_fmt);
1502        xilinx_drm_dp_sub_av_buf_init_sf(&dp_sub->av_buf, vid_fmt, gfx_fmt);
1503        xilinx_drm_dp_sub_av_buf_set_vid_clock_src(&dp_sub->av_buf,
1504                                                   !dp_sub->vid_clk_pl);
1505        xilinx_drm_dp_sub_av_buf_set_vid_timing_src(&dp_sub->av_buf, true);
1506        xilinx_drm_dp_sub_av_buf_set_aud_clock_src(&dp_sub->av_buf, true);
1507        xilinx_drm_dp_sub_av_buf_enable_buf(&dp_sub->av_buf);
1508        xilinx_drm_dp_sub_av_buf_enable_aud(&dp_sub->av_buf);
1509        xilinx_drm_dp_sub_aud_init(&dp_sub->aud);
1510}
1511EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_enable);
1512
1513/**
1514 * xilinx_drm_dp_sub_enable - Disable the DP subsystem
1515 * @dp_sub: DP subsystem
1516 *
1517 * Disable the DP subsystem.
1518 */
1519void xilinx_drm_dp_sub_disable(struct xilinx_drm_dp_sub *dp_sub)
1520{
1521        xilinx_drm_dp_sub_aud_deinit(&dp_sub->aud);
1522        xilinx_drm_dp_sub_av_buf_disable_aud(&dp_sub->av_buf);
1523        xilinx_drm_dp_sub_av_buf_disable_buf(&dp_sub->av_buf);
1524        xilinx_drm_dp_sub_av_buf_disable(&dp_sub->av_buf);
1525}
1526EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_disable);
1527
1528/* DP subsystem initialization functions */
1529
1530/**
1531 * xilinx_drm_dp_sub_of_get - Get the DP subsystem instance
1532 * @np: parent device node
1533 *
1534 * This function searches and returns a DP subsystem structure for
1535 * the parent device node, @np. The DP subsystem node should be a child node of
1536 * @np, with 'xlnx,dp-sub' property pointing to the DP device node. An instance
1537 * can be shared by multiple users.
1538 *
1539 * Return: corresponding DP subsystem structure if found. NULL if
1540 * the device node doesn't have 'xlnx,dp-sub' property, or -EPROBE_DEFER error
1541 * pointer if the the DP subsystem isn't found.
1542 */
1543struct xilinx_drm_dp_sub *xilinx_drm_dp_sub_of_get(struct device_node *np)
1544{
1545        struct device_node *xilinx_drm_dp_sub_node;
1546        struct xilinx_drm_dp_sub *found = NULL;
1547        struct xilinx_drm_dp_sub *dp_sub;
1548
1549        if (!of_find_property(np, "xlnx,dp-sub", NULL))
1550                return NULL;
1551
1552        xilinx_drm_dp_sub_node = of_parse_phandle(np, "xlnx,dp-sub", 0);
1553        if (xilinx_drm_dp_sub_node == NULL)
1554                return ERR_PTR(-EINVAL);
1555
1556        mutex_lock(&xilinx_drm_dp_sub_lock);
1557        list_for_each_entry(dp_sub, &xilinx_drm_dp_sub_list, list) {
1558                if (dp_sub->dev->of_node == xilinx_drm_dp_sub_node) {
1559                        found = dp_sub;
1560                        break;
1561                }
1562        }
1563        mutex_unlock(&xilinx_drm_dp_sub_lock);
1564
1565        of_node_put(xilinx_drm_dp_sub_node);
1566
1567        if (!found)
1568                return ERR_PTR(-EPROBE_DEFER);
1569
1570        return found;
1571}
1572EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_of_get);
1573
1574/**
1575 * xilinx_drm_dp_sub_put - Put the DP subsystem instance
1576 * @dp_sub: DP subsystem
1577 *
1578 * Put the DP subsystem instance @dp_sub.
1579 */
1580void xilinx_drm_dp_sub_put(struct xilinx_drm_dp_sub *dp_sub)
1581{
1582        /* no-op */
1583}
1584EXPORT_SYMBOL_GPL(xilinx_drm_dp_sub_put);
1585
1586/**
1587 * xilinx_drm_dp_register_device - Register the DP subsystem to the global list
1588 * @dp_sub: DP subsystem
1589 *
1590 * Register the DP subsystem instance to the global list
1591 */
1592static void xilinx_drm_dp_sub_register_device(struct xilinx_drm_dp_sub *dp_sub)
1593{
1594        mutex_lock(&xilinx_drm_dp_sub_lock);
1595        list_add_tail(&dp_sub->list, &xilinx_drm_dp_sub_list);
1596        mutex_unlock(&xilinx_drm_dp_sub_lock);
1597}
1598
1599/**
1600 * xilinx_drm_dp_register_device - Unregister the DP subsystem instance
1601 * @dp_sub: DP subsystem
1602 *
1603 * Unregister the DP subsystem instance from the global list
1604 */
1605static void
1606xilinx_drm_dp_sub_unregister_device(struct xilinx_drm_dp_sub *dp_sub)
1607{
1608        mutex_lock(&xilinx_drm_dp_sub_lock);
1609        list_del(&dp_sub->list);
1610        mutex_unlock(&xilinx_drm_dp_sub_lock);
1611}
1612
1613/**
1614 * xilinx_drm_dp_sub_parse_of - Parse the DP subsystem device tree node
1615 * @dp_sub: DP subsystem
1616 *
1617 * Parse the DP subsystem device tree node.
1618 *
1619 * Return: 0 on success, or the corresponding error code.
1620 */
1621static int xilinx_drm_dp_sub_parse_of(struct xilinx_drm_dp_sub *dp_sub)
1622{
1623        struct device_node *node = dp_sub->dev->of_node;
1624        struct xilinx_drm_dp_sub_layer *layer;
1625        const char *string;
1626        u32 fmt, i, size;
1627        bool ret;
1628
1629        ret = of_property_read_string(node, "xlnx,output-fmt", &string);
1630        if (ret < 0) {
1631                dev_err(dp_sub->dev, "No colormetry in DT\n");
1632                return ret;
1633        }
1634
1635        if (strcmp(string, "rgb") == 0) {
1636                fmt = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_RGB;
1637        } else if (strcmp(string, "ycrcb444") == 0) {
1638                fmt = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YCBCR444;
1639        } else if (strcmp(string, "ycrcb422") == 0) {
1640                fmt = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YCBCR422;
1641                fmt |= XILINX_DP_SUB_V_BLEND_OUTPUT_EN_DOWNSAMPLE;
1642        } else if (strcmp(string, "yonly") == 0) {
1643                fmt = XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_YONLY;
1644        } else {
1645                dev_err(dp_sub->dev, "Invalid output format in DT\n");
1646                return -EINVAL;
1647        }
1648
1649        xilinx_drm_writel(dp_sub->blend.base,
1650                          XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT, fmt);
1651
1652        if (fmt != XILINX_DP_SUB_V_BLEND_OUTPUT_VID_FMT_RGB) {
1653                u16 sdtv_coeffs[] = { 0x4c9, 0x864, 0x1d3,
1654                                      0x7d4d, 0x7ab3, 0x800,
1655                                      0x800, 0x794d, 0x7eb3 };
1656                u32 full_range_offsets[] = { 0x0, 0x8000000, 0x8000000 };
1657                u32 offset, i;
1658
1659                /* Hardcode SDTV coefficients. Can be runtime configurable */
1660                offset = XILINX_DP_SUB_V_BLEND_RGB2YCBCR_COEFF0;
1661                for (i = 0; i < XILINX_DP_SUB_V_BLEND_NUM_COEFF; i++)
1662                        xilinx_drm_writel(dp_sub->blend.base, offset + i * 4,
1663                                          sdtv_coeffs[i]);
1664
1665                offset = XILINX_DP_SUB_V_BLEND_LUMA_OUTCSC_OFFSET;
1666                for (i = 0; i < XILINX_DP_SUB_V_BLEND_NUM_OFFSET; i++)
1667                        xilinx_drm_writel(dp_sub->blend.base, offset + i * 4,
1668                                          full_range_offsets[i]);
1669        }
1670
1671        ret = of_property_read_bool(node, "xlnx,vid-primary");
1672        if (ret)
1673                dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_VID].primary = true;
1674        else
1675                dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_GFX].primary = true;
1676
1677        ret = of_property_read_string(node, "xlnx,vid-fmt", &string);
1678        if (!ret) {
1679                layer = &dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_VID];
1680                size = ARRAY_SIZE(av_buf_vid_fmts);
1681                layer->num_fmts = size;
1682                layer->drm_fmts = devm_kzalloc(dp_sub->dev,
1683                                               sizeof(*layer->drm_fmts) * size,
1684                                               GFP_KERNEL);
1685                if (!layer->drm_fmts)
1686                        return -ENOMEM;
1687
1688                for (i = 0; i < layer->num_fmts; i++) {
1689                        const struct xilinx_drm_dp_sub_fmt *fmt =
1690                                &av_buf_vid_fmts[i];
1691
1692                        if (strcmp(string, fmt->name) == 0)
1693                                layer->fmt = fmt;
1694
1695                        layer->drm_fmts[i] = fmt->drm_fmt;
1696                }
1697
1698                if (!layer->fmt) {
1699                        dev_info(dp_sub->dev, "Invalid vid-fmt in DT\n");
1700                        layer->fmt = &av_buf_vid_fmts[0];
1701                }
1702        }
1703
1704        ret = of_property_read_string(node, "xlnx,gfx-fmt", &string);
1705        if (!ret) {
1706                layer = &dp_sub->layers[XILINX_DRM_DP_SUB_LAYER_GFX];
1707                size = ARRAY_SIZE(av_buf_gfx_fmts);
1708                layer->num_fmts = size;
1709                layer->drm_fmts = devm_kzalloc(dp_sub->dev,
1710                                               sizeof(*layer->drm_fmts) * size,
1711                                               GFP_KERNEL);
1712                if (!layer->drm_fmts)
1713                        return -ENOMEM;
1714
1715                for (i = 0; i < layer->num_fmts; i++) {
1716                        const struct xilinx_drm_dp_sub_fmt *fmt =
1717                                &av_buf_gfx_fmts[i];
1718
1719                        if (strcmp(string, fmt->name) == 0)
1720                                layer->fmt = fmt;
1721
1722                        layer->drm_fmts[i] = fmt->drm_fmt;
1723                }
1724
1725                if (!layer->fmt) {
1726                        dev_info(dp_sub->dev, "Invalid vid-fmt in DT\n");
1727                        layer->fmt = &av_buf_gfx_fmts[0];
1728                }
1729        }
1730
1731        dp_sub->vid_clk_pl = of_property_read_bool(node, "xlnx,vid-clk-pl");
1732
1733        return 0;
1734}
1735
1736static int xilinx_drm_dp_sub_probe(struct platform_device *pdev)
1737{
1738        struct xilinx_drm_dp_sub *dp_sub;
1739        struct resource *res;
1740        int ret;
1741
1742        dp_sub = devm_kzalloc(&pdev->dev, sizeof(*dp_sub), GFP_KERNEL);
1743        if (!dp_sub)
1744                return -ENOMEM;
1745
1746        dp_sub->dev = &pdev->dev;
1747
1748        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "blend");
1749        dp_sub->blend.base = devm_ioremap_resource(&pdev->dev, res);
1750        if (IS_ERR(dp_sub->blend.base))
1751                return PTR_ERR(dp_sub->blend.base);
1752
1753        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "av_buf");
1754        dp_sub->av_buf.base = devm_ioremap_resource(&pdev->dev, res);
1755        if (IS_ERR(dp_sub->av_buf.base))
1756                return PTR_ERR(dp_sub->av_buf.base);
1757
1758        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud");
1759        dp_sub->aud.base = devm_ioremap_resource(&pdev->dev, res);
1760        if (IS_ERR(dp_sub->aud.base))
1761                return PTR_ERR(dp_sub->aud.base);
1762
1763        dp_sub->layers[0].id = XILINX_DRM_DP_SUB_LAYER_VID;
1764        dp_sub->layers[0].offset = 0;
1765        dp_sub->layers[0].avail = true;
1766        dp_sub->layers[0].other = &dp_sub->layers[1];
1767
1768        dp_sub->layers[1].id = XILINX_DRM_DP_SUB_LAYER_GFX;
1769        dp_sub->layers[1].offset = 4;
1770        dp_sub->layers[1].avail = true;
1771        dp_sub->layers[1].other = &dp_sub->layers[0];
1772
1773        ret = xilinx_drm_dp_sub_parse_of(dp_sub);
1774        if (ret)
1775                return ret;
1776
1777        platform_set_drvdata(pdev, dp_sub);
1778
1779        xilinx_drm_dp_sub_register_device(dp_sub);
1780
1781        dev_info(dp_sub->dev, "Xilinx DisplayPort Subsystem is probed\n");
1782
1783        return 0;
1784}
1785
1786static int xilinx_drm_dp_sub_remove(struct platform_device *pdev)
1787{
1788        struct xilinx_drm_dp_sub *dp_sub = platform_get_drvdata(pdev);
1789
1790        xilinx_drm_dp_sub_unregister_device(dp_sub);
1791
1792        return 0;
1793}
1794
1795static const struct of_device_id xilinx_drm_dp_sub_of_id_table[] = {
1796        { .compatible = "xlnx,dp-sub" },
1797        { }
1798};
1799MODULE_DEVICE_TABLE(of, xilinx_drm_dp_sub_of_id_table);
1800
1801static struct platform_driver xilinx_drm_dp_sub_driver = {
1802        .driver = {
1803                .name           = "xilinx-drm-dp-sub",
1804                .of_match_table = xilinx_drm_dp_sub_of_id_table,
1805        },
1806        .probe  = xilinx_drm_dp_sub_probe,
1807        .remove = xilinx_drm_dp_sub_remove,
1808};
1809
1810module_platform_driver(xilinx_drm_dp_sub_driver);
1811
1812MODULE_DESCRIPTION("Xilinx DisplayPort Subsystem Driver");
1813MODULE_LICENSE("GPL v2");
1814