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