2 * Xilinx FPGA SDI Tx Controller driver.
4 * Copyright (c) 2017 Xilinx Pvt., Ltd
6 * Contacts: Saurabh Sengar <saurabhs@xilinx.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <drm/drm_crtc_helper.h>
15 #include <linux/component.h>
16 #include <linux/device.h>
17 #include <linux/list.h>
18 #include <linux/of_device.h>
19 #include <linux/of_graph.h>
20 #include <linux/phy/phy.h>
21 #include <video/videomode.h>
22 #include "xilinx_drm_sdi.h"
23 #include "xilinx_vtc.h"
25 /* SDI register offsets */
26 #define XSDI_TX_RST_CTRL 0x00
27 #define XSDI_TX_MDL_CTRL 0x04
28 #define XSDI_TX_GLBL_IER 0x0C
29 #define XSDI_TX_ISR_STAT 0x10
30 #define XSDI_TX_IER_STAT 0x14
31 #define XSDI_TX_ST352_LINE 0x18
32 #define XSDI_TX_ST352_DATA_CH0 0x1C
33 #define XSDI_TX_VER 0x3C
34 #define XSDI_TX_SYS_CFG 0x40
35 #define XSDI_TX_STS_SB_TDATA 0x60
36 #define XSDI_TX_AXI4S_STS1 0x68
37 #define XSDI_TX_AXI4S_STS2 0x6C
39 /* MODULE_CTRL register masks */
40 #define XSDI_TX_CTRL_MDL_EN_MASK BIT(0)
41 #define XSDI_TX_CTRL_OUT_EN_MASK BIT(1)
42 #define XSDI_TX_CTRL_M_MASK BIT(7)
43 #define XSDI_TX_CTRL_INS_CRC_MASK BIT(12)
44 #define XSDI_TX_CTRL_INS_ST352_MASK BIT(13)
45 #define XSDI_TX_CTRL_OVR_ST352_MASK BIT(14)
46 #define XSDI_TX_CTRL_INS_SYNC_BIT_MASK BIT(16)
47 #define XSDI_TX_CTRL_SD_BITREP_BYPASS_MASK BIT(17)
48 #define XSDI_TX_CTRL_USE_ANC_IN_MASK BIT(18)
49 #define XSDI_TX_CTRL_INS_LN_MASK BIT(19)
50 #define XSDI_TX_CTRL_INS_EDH_MASK BIT(20)
51 #define XSDI_TX_CTRL_MODE_MASK 0x7
52 #define XSDI_TX_CTRL_MUX_MASK 0x7
53 #define XSDI_TX_CTRL_MODE_SHIFT 4
54 #define XSDI_TX_CTRL_M_SHIFT 7
55 #define XSDI_TX_CTRL_MUX_SHIFT 8
56 #define XSDI_TX_CTRL_INS_CRC_SHIFT 12
57 #define XSDI_TX_CTRL_INS_ST352_SHIFT 13
58 #define XSDI_TX_CTRL_OVR_ST352_SHIFT 14
59 #define XSDI_TX_CTRL_ST352_F2_EN_SHIFT 15
60 #define XSDI_TX_CTRL_INS_SYNC_BIT_SHIFT 16
61 #define XSDI_TX_CTRL_SD_BITREP_BYPASS_SHIFT 17
62 #define XSDI_TX_CTRL_USE_ANC_IN_SHIFT 18
63 #define XSDI_TX_CTRL_INS_LN_SHIFT 19
64 #define XSDI_TX_CTRL_INS_EDH_SHIFT 20
66 /* TX_ST352_LINE register masks */
67 #define XSDI_TX_ST352_LINE_MASK GENMASK(10, 0)
68 #define XSDI_TX_ST352_LINE_F2_SHIFT 16
70 /* ISR STAT register masks */
71 #define XSDI_GTTX_RSTDONE_INTR_MASK BIT(0)
72 #define XSDI_TX_CE_ALIGN_ERR_INTR_MASK BIT(1)
73 #define XSDI_AXI4S_VID_LOCK_INTR_MASK BIT(8)
74 #define XSDI_OVERFLOW_INTR_MASK BIT(9)
75 #define XSDI_UNDERFLOW_INTR_MASK BIT(10)
76 #define XSDI_IER_EN_MASK (XSDI_GTTX_RSTDONE_INTR_MASK | \
77 XSDI_TX_CE_ALIGN_ERR_INTR_MASK | \
78 XSDI_OVERFLOW_INTR_MASK | \
79 XSDI_UNDERFLOW_INTR_MASK)
81 /* RST_CTRL_OFFSET masks */
82 #define XSDI_TX_BRIDGE_CTRL_EN_MASK BIT(8)
83 #define XSDI_TX_AXI4S_CTRL_EN_MASK BIT(9)
84 #define XSDI_TX_CTRL_EN_MASK BIT(0)
86 /* STS_SB_TX_TDATA masks */
87 #define XSDI_TX_TDATA_DONE_MASK BIT(0)
88 #define XSDI_TX_TDATA_FAIL_MASK BIT(1)
89 #define XSDI_TX_TDATA_GT_RESETDONE_MASK BIT(2)
90 #define XSDI_TX_TDATA_SLEW_RATE_MASK BIT(3)
91 #define XSDI_TX_TDATA_TXPLLCLKSEL_MASK GENMASK(5, 4)
92 #define XSDI_TX_TDATA_GT_SYSCLKSEL_MASK GENMASK(7, 6)
93 #define XSDI_TX_TDATA_FABRIC_RST_MASK BIT(8)
94 #define XSDI_TX_TDATA_DRP_FAIL_MASK BIT(9)
95 #define XSDI_TX_TDATA_FAIL_CODE_MASK GENMASK(14, 12)
96 #define XSDI_TX_TDATA_DRP_FAIL_CNT_MASK 0xFF0000
97 #define XSDI_TX_TDATA_GT_QPLL0LOCK_MASK BIT(24)
98 #define XSDI_TX_TDATA_GT_QPLL1LOCK_MASK BIT(25)
100 #define SDI_MAX_DATASTREAM 8
102 #define XSDI_TX_MUX_SD_HD_3GA 0
103 #define XSDI_TX_MUX_3GB 1
104 #define XSDI_TX_MUX_8STREAM_6G_12G 2
105 #define XSDI_TX_MUX_4STREAM_6G 3
106 #define XSDI_TX_MUX_16STREAM_12G 4
108 #define PIXELS_PER_CLK 2
109 #define XSDI_CH_SHIFT 29
110 #define XST352_PROG_PIC_MASK BIT(6)
111 #define XST352_PROG_TRANS_MASK BIT(7)
112 #define XST352_2048_SHIFT BIT(6)
113 #define ST352_BYTE3 0x00
114 #define ST352_BYTE4 0x01
115 #define INVALID_VALUE -1
116 #define GT_TIMEOUT 500
118 static LIST_HEAD(xilinx_sdi_list);
119 static DEFINE_MUTEX(xilinx_sdi_lock);
121 * enum payload_line_1 - Payload Ids Line 1 number
122 * @PAYLD_LN1_HD_3_6_12G: line 1 HD,3G,6G or 12G mode value
123 * @PAYLD_LN1_SDPAL: line 1 SD PAL mode value
124 * @PAYLD_LN1_SDNTSC: line 1 SD NTSC mode value
126 enum payload_line_1 {
127 PAYLD_LN1_HD_3_6_12G = 10,
129 PAYLD_LN1_SDNTSC = 13
133 * enum payload_line_2 - Payload Ids Line 2 number
134 * @PAYLD_LN2_HD_3_6_12G: line 2 HD,3G,6G or 12G mode value
135 * @PAYLD_LN2_SDPAL: line 2 SD PAL mode value
136 * @PAYLD_LN2_SDNTSC: line 2 SD NTSC mode value
138 enum payload_line_2 {
139 PAYLD_LN2_HD_3_6_12G = 572,
140 PAYLD_LN2_SDPAL = 322,
141 PAYLD_LN2_SDNTSC = 276
145 * enum sdi_modes - SDI modes
146 * @XSDI_MODE_HD: HD mode
147 * @XSDI_MODE_SD: SD mode
148 * @XSDI_MODE_3GA: 3GA mode
149 * @XSDI_MODE_3GB: 3GB mode
150 * @XSDI_MODE_6G: 6G mode
151 * @XSDI_MODE_12G: 12G mode
163 * struct xilinx_sdi - Core configuration SDI Tx subsystem device structure
164 * @encoder: DRM encoder structure
165 * @connector: DRM connector structure
166 * @vtc: Pointer to VTC structure
167 * @dev: device structure
168 * @base: Base address of SDI subsystem
169 * @mode_flags: SDI operation mode related flags
170 * @wait_event: wait event
171 * @event_received: wait event status
172 * @list: entry in the global SDI subsystem list
173 * @vblank_fn: vblank handler
174 * @vblank_data: vblank data to be used in vblank_fn
175 * @sdi_mode: configurable SDI mode parameter, supported values are:
182 * @sdi_mod_prop_val: configurable SDI mode parameter value
183 * @sdi_data_strm: configurable SDI data stream parameter
184 * @sdi_data_strm_prop_val: configurable number of SDI data streams
185 * value currently supported are 2, 4 and 8
186 * @is_frac_prop: configurable SDI fractional fps parameter
187 * @is_frac_prop_val: configurable SDI fractional fps parameter value
190 struct drm_encoder encoder;
191 struct drm_connector connector;
192 struct xilinx_vtc *vtc;
196 wait_queue_head_t wait_event;
198 struct list_head list;
199 void (*vblank_fn)(void *);
201 struct drm_property *sdi_mode;
202 u32 sdi_mod_prop_val;
203 struct drm_property *sdi_data_strm;
204 u32 sdi_data_strm_prop_val;
205 struct drm_property *is_frac_prop;
206 bool is_frac_prop_val;
210 * struct xilinx_sdi_display_config - SDI supported modes structure
211 * @mode: drm display mode
212 * @st352_byt2: st352 byte 2 value
213 * index 0 : value for integral fps
214 * index 1 : value for fractional fps
215 * @st352_byt1: st352 byte 1 value
216 * index 0 : value for HD mode
217 * index 1 : value for SD mode
218 * index 2 : value for 3GA
219 * index 3 : value for 3GB
220 * index 4 : value for 6G
221 * index 5 : value for 12G
223 struct xlnx_sdi_display_config {
224 struct drm_display_mode mode;
230 * xlnx_sdi_modes - SDI DRM modes
232 static const struct xlnx_sdi_display_config xlnx_sdi_modes[] = {
233 /* 0 - dummy, VICs start at 1 */
235 /* SD: 720x480i@60Hz */
236 {{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
237 801, 858, 0, 240, 244, 247, 262, 0,
238 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
239 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
240 .vrefresh = 60, }, {0x7, 0x6},
241 {0x81, 0x81, 0x81, 0x81, 0x81, 0x81} },
242 /* SD: 720x576i@50Hz */
243 {{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
244 795, 864, 0, 288, 290, 293, 312, 0,
245 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
246 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
247 .vrefresh = 50, }, {0x9, 0x9},
248 {0x81, 0x81, 0x81, 0x81, 0x81, 0x81} },
249 /* HD: 1280x720@25Hz */
250 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
251 2990, 3960, 0, 720, 725, 730, 750, 0,
252 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
253 .vrefresh = 25, }, {0x5, 0x5},
254 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
255 /* HD: 1280x720@24Hz */
256 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
257 3155, 4125, 0, 720, 725, 730, 750, 0,
258 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
259 .vrefresh = 24, }, {0x3, 0x2},
260 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
261 /* HD: 1280x720@30Hz */
262 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
263 2330, 3300, 0, 720, 725, 730, 750, 0,
264 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
265 .vrefresh = 30, }, {0x7, 0x6},
266 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
267 /* HD: 1280x720@50Hz */
268 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
269 1760, 1980, 0, 720, 725, 730, 750, 0,
270 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
271 .vrefresh = 50, }, {0x9, 0x9},
272 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
273 /* HD: 1280x720@60Hz */
274 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
275 1430, 1650, 0, 720, 725, 730, 750, 0,
276 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
277 .vrefresh = 60, }, {0xB, 0xA},
278 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
279 /* HD: 1920x1080@24Hz */
280 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
281 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
282 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
283 .vrefresh = 24, }, {0x3, 0x2},
284 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
285 /* HD: 1920x1080@25Hz */
286 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
287 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
288 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
289 .vrefresh = 25, }, {0x5, 0x5},
290 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
291 /* HD: 1920x1080@30Hz */
292 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
293 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
294 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
295 .vrefresh = 30, }, {0x7, 0x6},
296 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
297 /* HD: 1920x1080i@48Hz */
298 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2291,
299 2379, 2750, 0, 540, 542, 547, 562, 0,
300 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
301 DRM_MODE_FLAG_INTERLACE),
302 .vrefresh = 48, }, {0x3, 0x2},
303 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
304 /* HD: 1920x1080i@50Hz */
305 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
306 2492, 2640, 0, 540, 542, 547, 562, 0,
307 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
308 DRM_MODE_FLAG_INTERLACE),
309 .vrefresh = 50, }, {0x5, 0x5},
310 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
311 /* HD: 1920x1080i@60Hz */
312 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
313 2052, 2200, 0, 540, 542, 547, 562, 0,
314 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
315 DRM_MODE_FLAG_INTERLACE),
316 .vrefresh = 60, }, {0x7, 0x6},
317 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
318 /* HD: 1920x1080sf@24Hz */
319 {{ DRM_MODE("1920x1080sf", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2291,
320 2379, 2750, 0, 540, 542, 547, 562, 0,
321 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
322 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN),
323 .vrefresh = 48, }, {0x3, 0x2},
324 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
325 /* HD: 1920x1080sf@25Hz */
326 {{ DRM_MODE("1920x1080sf", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
327 2492, 2640, 0, 540, 542, 547, 562, 0,
328 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
329 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN),
330 .vrefresh = 50, }, {0x5, 0x5},
331 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
332 /* HD: 1920x1080sf@30Hz */
333 {{ DRM_MODE("1920x1080sf", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
334 2052, 2200, 0, 540, 542, 547, 562, 0,
335 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
336 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN),
337 .vrefresh = 60, }, {0x7, 0x6},
338 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
339 /* HD: 2048x1080i@48Hz */
340 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2377,
341 2421, 2750, 0, 540, 542, 547, 562, 0,
342 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
343 DRM_MODE_FLAG_INTERLACE),
344 .vrefresh = 48, }, {0x3, 0x2},
345 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
346 /* HD: 2048x1080i@50Hz */
347 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2322,
348 2366, 2640, 0, 540, 542, 547, 562, 0,
349 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
350 DRM_MODE_FLAG_INTERLACE),
351 .vrefresh = 50, }, {0x5, 0x5},
352 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
353 /* HD: 2048x1080i@60Hz */
354 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2114,
355 2134, 2200, 0, 540, 542, 547, 562, 0,
356 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
357 DRM_MODE_FLAG_INTERLACE),
358 .vrefresh = 60, }, {0x7, 0x6},
359 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
360 /* HD: 2048x1080sf@24Hz */
361 {{ DRM_MODE("2048x1080sf", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2377,
362 2421, 2750, 0, 540, 542, 547, 562, 0,
363 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
364 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN),
365 .vrefresh = 48, }, {0x3, 0x2},
366 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
367 /* HD: 2048x1080sf@25Hz */
368 {{ DRM_MODE("2048x1080sf", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2322,
369 2366, 2640, 0, 540, 542, 547, 562, 0,
370 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
371 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN),
372 .vrefresh = 50, }, {0x5, 0x5},
373 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
374 /* HD: 2048x1080sf@30Hz */
375 {{ DRM_MODE("2048x1080sf", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2114,
376 2134, 2200, 0, 540, 542, 547, 562, 0,
377 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
378 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN),
379 .vrefresh = 60, }, {0x7, 0x6},
380 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
381 /* HD: 2048x1080@30Hz */
382 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2114,
383 2134, 2200, 0, 1080, 1084, 1089, 1125, 0,
384 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
385 .vrefresh = 30, }, {0x7, 0x6},
386 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
387 /* HD: 2048x1080@25Hz */
388 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2448,
389 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
390 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
391 .vrefresh = 25, }, {0x5, 0x5},
392 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
393 /* HD: 2048x1080@24Hz */
394 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2558,
395 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
396 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
397 .vrefresh = 24, }, {0x3, 0x2},
398 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
399 /* 3G: 1920x1080@48Hz */
400 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2558,
401 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
402 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
403 .vrefresh = 48, }, {0x8, 0x4},
404 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
405 /* 3G: 1920x1080@50Hz */
406 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
407 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
408 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
409 .vrefresh = 50, }, {0x9, 0x9},
410 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
411 /* 3G: 1920x1080@60Hz */
412 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
413 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
414 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
415 .vrefresh = 60, }, {0xB, 0xA},
416 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
417 /* 3G: 2048x1080@60Hz */
418 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2136,
419 2180, 2200, 0, 1080, 1084, 1089, 1125, 0,
420 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
421 .vrefresh = 60, }, {0xB, 0xA},
422 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
423 /* 3G: 2048x1080@50Hz */
424 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2448,
425 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
426 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
427 .vrefresh = 50, }, {0x9, 0x9},
428 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
429 /* 3G: 2048x1080@48Hz */
430 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2558,
431 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
432 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
433 .vrefresh = 48, }, {0x8, 0x4},
434 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
435 /* 3G-B: 1920x1080i@96Hz */
436 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2291,
437 2379, 2750, 0, 1080, 1084, 1094, 1124, 0,
438 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
439 DRM_MODE_FLAG_INTERLACE),
440 .vrefresh = 96, }, {0x8, 0x4},
441 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
442 /* 3G-B: 1920x1080i@100Hz */
443 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
444 2492, 2640, 0, 1080, 1084, 1094, 1124, 0,
445 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
446 DRM_MODE_FLAG_INTERLACE),
447 .vrefresh = 100, }, {0x9, 0x9},
448 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
449 /* 3G-B: 1920x1080i@120Hz */
450 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
451 2052, 2200, 0, 1080, 1084, 1094, 1124, 0,
452 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
453 DRM_MODE_FLAG_INTERLACE),
454 .vrefresh = 120, }, {0xB, 0xA},
455 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
456 /* 3G-B: 2048x1080i@96Hz */
457 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2377,
458 2421, 2750, 0, 1080, 1084, 1094, 1124, 0,
459 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
460 DRM_MODE_FLAG_INTERLACE),
461 .vrefresh = 96, }, {0x8, 0x4},
462 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
463 /* 3G-B: 2048x1080i@100Hz */
464 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2322,
465 2366, 2640, 0, 1080, 1084, 1094, 1124, 0,
466 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
467 DRM_MODE_FLAG_INTERLACE),
468 .vrefresh = 100, }, {0x9, 0x9},
469 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
470 /* 3G-B: 2048x1080i@120Hz */
471 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2114,
472 2134, 2200, 0, 1080, 1084, 1094, 1124, 0,
473 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
474 DRM_MODE_FLAG_INTERLACE),
475 .vrefresh = 120, }, {0xB, 0xA},
476 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
477 /* 6G: 3840x2160@30Hz */
478 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
479 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
480 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
481 .vrefresh = 30, }, {0x7, 0x6},
482 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
483 /* 6G: 3840x2160@25Hz */
484 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896,
485 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
486 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
487 .vrefresh = 25, }, {0x5, 0x5},
488 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
489 /* 6G: 3840x2160@24Hz */
490 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
491 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
492 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
493 .vrefresh = 24, }, {0x3, 0x2},
494 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
495 /* 6G: 4096x2160@24Hz */
496 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 296704, 4096, 5116,
497 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
498 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
499 .vrefresh = 24, }, {0x3, 0x2},
500 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
501 /* 6G: 4096x2160@25Hz */
502 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064,
503 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
504 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
505 .vrefresh = 25, }, {0x5, 0x5},
506 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
507 /* 6G: 4096x2160@30Hz */
508 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 296704, 4096, 4184,
509 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
510 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
511 .vrefresh = 30, }, {0x7, 0x6},
512 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
513 /* 12G: 3840x2160@48Hz */
514 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 5116,
515 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
516 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
517 .vrefresh = 48, }, {0x8, 0x4},
518 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
519 /* 12G: 3840x2160@50Hz */
520 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
521 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
522 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
523 .vrefresh = 50, }, {0x9, 0x9},
524 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
525 /* 12G: 3840x2160@60Hz */
526 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
527 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
528 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
529 .vrefresh = 60, }, {0xB, 0xA},
530 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
531 /* 12G: 4096x2160@48Hz */
532 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5116,
533 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
534 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
535 .vrefresh = 48, }, {0x8, 0x4},
536 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
537 /* 12G: 4096x2160@50Hz */
538 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064,
539 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
540 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
541 .vrefresh = 50, }, {0x9, 0x9},
542 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
543 /* 12G: 4096x2160@60Hz */
544 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 593408, 4096, 4184,
545 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
546 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
547 .vrefresh = 60, }, {0xB, 0xA},
548 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
551 #define connector_to_sdi(c) container_of(c, struct xilinx_sdi, connector)
552 #define encoder_to_sdi(e) container_of(e, struct xilinx_sdi, encoder)
555 * xilinx_sdi_writel - Memory mapped SDI Tx register write
556 * @base: Pointer to SDI Tx registers base
557 * @offset: Register offset
558 * @val: value to be written
560 * This function writes the value to SDI TX registers
562 static inline void xilinx_sdi_writel(void __iomem *base, int offset, u32 val)
564 writel(val, base + offset);
568 * xilinx_sdi_readl - Memory mapped SDI Tx register read
569 * @base: Pointer to SDI Tx registers base
570 * @offset: Register offset
572 * Return: The contents of the SDI Tx register
574 * This function returns the contents of the corresponding SDI Tx register.
576 static inline u32 xilinx_sdi_readl(void __iomem *base, int offset)
578 return readl(base + offset);
582 * xilinx_en_axi4s - Enable SDI Tx AXI4S-to-Video core
583 * @sdi: Pointer to SDI Tx structure
585 * This function enables the SDI Tx AXI4S-to-Video core.
587 static void xilinx_en_axi4s(struct xilinx_sdi *sdi)
591 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
592 data |= XSDI_TX_AXI4S_CTRL_EN_MASK;
593 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
597 * xilinx_en_bridge - Enable SDI Tx bridge
598 * @sdi: Pointer to SDI Tx structure
600 * This function enables the SDI Tx bridge.
602 static void xilinx_en_bridge(struct xilinx_sdi *sdi)
606 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
607 data |= XSDI_TX_BRIDGE_CTRL_EN_MASK;
608 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
612 * xilinx_sdi_set_default_drm_properties - Configure SDI DRM
613 * properties with their default values
614 * @sdi: SDI structure having the updated user parameters
617 xilinx_sdi_set_default_drm_properties(struct xilinx_sdi *sdi)
619 drm_object_property_set_value(&sdi->connector.base,
621 drm_object_property_set_value(&sdi->connector.base,
622 sdi->sdi_data_strm, 0);
623 drm_object_property_set_value(&sdi->connector.base,
624 sdi->is_frac_prop, 0);
628 * xilinx_sdi_irq_handler - SDI Tx interrupt
632 * Return: IRQ_HANDLED for all cases.
634 * This is the compact GT ready interrupt.
636 static irqreturn_t xilinx_sdi_irq_handler(int irq, void *data)
638 struct xilinx_sdi *sdi = (struct xilinx_sdi *)data;
641 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_ISR_STAT);
643 if (reg & XSDI_GTTX_RSTDONE_INTR_MASK)
644 dev_dbg(sdi->dev, "GT reset interrupt received\n");
645 if (reg & XSDI_TX_CE_ALIGN_ERR_INTR_MASK)
646 dev_err_ratelimited(sdi->dev, "SDI SD CE align error\n");
647 if (reg & XSDI_OVERFLOW_INTR_MASK)
648 dev_err_ratelimited(sdi->dev, "AXI-4 Stream Overflow error\n");
649 if (reg & XSDI_UNDERFLOW_INTR_MASK)
650 dev_err_ratelimited(sdi->dev, "AXI-4 Stream Underflow error\n");
651 xilinx_sdi_writel(sdi->base, XSDI_TX_ISR_STAT,
652 reg & ~(XSDI_AXI4S_VID_LOCK_INTR_MASK));
654 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_STS_SB_TDATA);
655 if (reg & XSDI_TX_TDATA_GT_RESETDONE_MASK) {
656 sdi->event_received = true;
657 wake_up_interruptible(&sdi->wait_event);
663 * xilinx_sdi_set_payload_line - set ST352 packet line number
664 * @sdi: Pointer to SDI Tx structure
665 * @line_1: line number used to insert st352 packet for field 1.
666 * @line_2: line number used to insert st352 packet for field 2.
668 * This function set 352 packet line number.
670 static void xilinx_sdi_set_payload_line(struct xilinx_sdi *sdi,
671 u32 line_1, u32 line_2)
675 data = ((line_1 & XSDI_TX_ST352_LINE_MASK) |
676 ((line_2 & XSDI_TX_ST352_LINE_MASK) <<
677 XSDI_TX_ST352_LINE_F2_SHIFT));
679 xilinx_sdi_writel(sdi->base, XSDI_TX_ST352_LINE, data);
681 data = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
682 data |= (1 << XSDI_TX_CTRL_ST352_F2_EN_SHIFT);
684 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, data);
688 * xilinx_sdi_set_payload_data - set ST352 packet payload
689 * @sdi: Pointer to SDI Tx structure
690 * @data_strm: data stream number
691 * @payload: st352 packet payload
693 * This function set ST352 payload data to corresponding stream.
695 static void xilinx_sdi_set_payload_data(struct xilinx_sdi *sdi,
696 u32 data_strm, u32 payload)
698 xilinx_sdi_writel(sdi->base,
699 (XSDI_TX_ST352_DATA_CH0 + (data_strm * 4)), payload);
703 * xilinx_sdi_set_display_disable - Disable the SDI Tx IP core enable
705 * @sdi: SDI structure having the updated user parameters
707 * This function takes the SDI strucure and disables the core enable bit
708 * of core configuration register.
710 static void xilinx_sdi_set_display_disable(struct xilinx_sdi *sdi)
714 for (i = 0; i < SDI_MAX_DATASTREAM; i++)
715 xilinx_sdi_set_payload_data(sdi, i, 0);
717 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 0);
718 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, 0);
722 * xilinx_sdi_payload_config - config the SDI payload parameters
723 * @sdi: pointer Xilinx SDI Tx structure
724 * @mode: display mode
726 * This function config the SDI st352 payload parameter.
728 static void xilinx_sdi_payload_config(struct xilinx_sdi *sdi, u32 mode)
730 u32 payload_1, payload_2;
734 payload_1 = PAYLD_LN1_SDPAL;
735 payload_2 = PAYLD_LN2_SDPAL;
742 payload_1 = PAYLD_LN1_HD_3_6_12G;
743 payload_2 = PAYLD_LN2_HD_3_6_12G;
751 xilinx_sdi_set_payload_line(sdi, payload_1, payload_2);
755 * xilinx_set_sdi_mode - Set mode parameters in SDI Tx
756 * @sdi: pointer Xilinx SDI Tx structure
757 * @mode: SDI Tx display mode
758 * @is_frac: 0 - integer 1 - fractional
759 * @mux_ptrn: specifiy the data stream interleaving pattern to be used
760 * This function config the SDI st352 payload parameter.
762 static void xilinx_set_sdi_mode(struct xilinx_sdi *sdi, u32 mode,
763 bool is_frac, u32 mux_ptrn)
767 xilinx_sdi_payload_config(sdi, mode);
769 data = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
770 data &= ~((XSDI_TX_CTRL_MODE_MASK << XSDI_TX_CTRL_MODE_SHIFT) |
771 (XSDI_TX_CTRL_M_MASK) | (XSDI_TX_CTRL_MUX_MASK
772 << XSDI_TX_CTRL_MUX_SHIFT));
774 data |= (((mode & XSDI_TX_CTRL_MODE_MASK)
775 << XSDI_TX_CTRL_MODE_SHIFT) |
776 (is_frac << XSDI_TX_CTRL_M_SHIFT) |
777 ((mux_ptrn & XSDI_TX_CTRL_MUX_MASK) << XSDI_TX_CTRL_MUX_SHIFT));
779 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, data);
783 * xilinx_sdi_set_config_parameters - Configure SDI Tx registers with parameters
784 * given from user application.
785 * @sdi: SDI structure having the updated user parameters
787 * This function takes the SDI structure having drm_property parameters
788 * configured from user application and writes them into SDI IP registers.
790 static void xilinx_sdi_set_config_parameters(struct xilinx_sdi *sdi)
793 int mux_ptrn = INVALID_VALUE;
796 mode = sdi->sdi_mod_prop_val;
797 is_frac = sdi->is_frac_prop_val;
801 mux_ptrn = XSDI_TX_MUX_SD_HD_3GA;
804 mux_ptrn = XSDI_TX_MUX_3GB;
807 if (sdi->sdi_data_strm_prop_val == 4)
808 mux_ptrn = XSDI_TX_MUX_4STREAM_6G;
809 else if (sdi->sdi_data_strm_prop_val == 8)
810 mux_ptrn = XSDI_TX_MUX_8STREAM_6G_12G;
813 if (sdi->sdi_data_strm_prop_val == 8)
814 mux_ptrn = XSDI_TX_MUX_8STREAM_6G_12G;
820 if (mux_ptrn == INVALID_VALUE) {
821 dev_err(sdi->dev, "%d data stream not supported for %d mode",
822 sdi->sdi_data_strm_prop_val, mode);
825 xilinx_set_sdi_mode(sdi, mode, is_frac, mux_ptrn);
829 * xilinx_sdi_connector_set_property - implementation of drm_connector_funcs
830 * set_property invoked by IOCTL call to DRM_IOCTL_MODE_OBJ_SETPROPERTY
832 * @base_connector: pointer Xilinx SDI connector
833 * @property: pointer to the drm_property structure
834 * @value: SDI parameter value that is configured from user application
836 * This function takes a drm_property name and value given from user application
837 * and update the SDI structure property varabiles with the values.
838 * These values are later used to configure the SDI Rx IP.
840 * Return: 0 on success OR -EINVAL if setting property fails
843 xilinx_sdi_connector_set_property(struct drm_connector *base_connector,
844 struct drm_property *property,
847 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
849 if (property == sdi->sdi_mode)
850 sdi->sdi_mod_prop_val = (unsigned int)value;
851 else if (property == sdi->sdi_data_strm)
852 sdi->sdi_data_strm_prop_val = (unsigned int)value;
853 else if (property == sdi->is_frac_prop)
854 sdi->is_frac_prop_val = !!value;
861 * xilinx_sdi_get_mode_id - Search for a video mode in the supported modes table
863 * @mode: mode being searched
865 * Return: true if mode is found
867 static int xilinx_sdi_get_mode_id(struct drm_display_mode *mode)
871 for (i = 0; i < ARRAY_SIZE(xlnx_sdi_modes); i++)
872 if (drm_mode_equal(&xlnx_sdi_modes[i].mode, mode))
878 * xilinx_sdi_drm_add_modes - Adds SDI supported modes
879 * @connector: pointer Xilinx SDI connector
881 * Return: Count of modes added
883 * This function adds the SDI modes supported and returns its count
885 static int xilinx_sdi_drm_add_modes(struct drm_connector *connector)
887 int i, num_modes = 0;
888 struct drm_display_mode *mode;
889 struct drm_device *dev = connector->dev;
891 for (i = 0; i < ARRAY_SIZE(xlnx_sdi_modes); i++) {
892 const struct drm_display_mode *ptr = &xlnx_sdi_modes[i].mode;
894 mode = drm_mode_duplicate(dev, ptr);
896 drm_mode_probed_add(connector, mode);
903 static int xilinx_sdi_connector_dpms(struct drm_connector *connector,
906 return drm_helper_connector_dpms(connector, mode);
909 static enum drm_connector_status
910 xilinx_sdi_detect(struct drm_connector *connector, bool force)
912 return connector_status_connected;
915 static void xilinx_sdi_connector_destroy(struct drm_connector *connector)
917 drm_connector_unregister(connector);
918 drm_connector_cleanup(connector);
919 connector->dev = NULL;
922 static const struct drm_connector_funcs xilinx_sdi_connector_funcs = {
923 .dpms = xilinx_sdi_connector_dpms,
924 .detect = xilinx_sdi_detect,
925 .fill_modes = drm_helper_probe_single_connector_modes,
926 .destroy = xilinx_sdi_connector_destroy,
927 .set_property = xilinx_sdi_connector_set_property,
930 static struct drm_encoder *
931 xilinx_sdi_best_encoder(struct drm_connector *connector)
933 return &(connector_to_sdi(connector)->encoder);
936 static int xilinx_sdi_get_modes(struct drm_connector *connector)
938 return xilinx_sdi_drm_add_modes(connector);
941 static struct drm_connector_helper_funcs xilinx_sdi_connector_helper_funcs = {
942 .get_modes = xilinx_sdi_get_modes,
943 .best_encoder = xilinx_sdi_best_encoder,
947 * xilinx_sdi_drm_connector_create_property - create SDI connector properties
949 * @base_connector: pointer to Xilinx SDI connector
951 * This function takes the xilinx SDI connector component and defines
952 * the drm_property variables with their default values.
955 xilinx_sdi_drm_connector_create_property(struct drm_connector *base_connector)
957 struct drm_device *dev = base_connector->dev;
958 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
960 sdi->is_frac_prop = drm_property_create_bool(dev, 1, "is_frac");
961 sdi->sdi_mode = drm_property_create_range(dev, 0,
963 sdi->sdi_data_strm = drm_property_create_range(dev, 0,
964 "sdi_data_stream", 2, 8);
968 * xilinx_sdi_drm_connector_attach_property - attach SDI connector
971 * @base_connector: pointer to Xilinx SDI connector
974 xilinx_sdi_drm_connector_attach_property(struct drm_connector *base_connector)
976 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
977 struct drm_mode_object *obj = &base_connector->base;
980 drm_object_attach_property(obj, sdi->sdi_mode, 0);
982 if (sdi->sdi_data_strm)
983 drm_object_attach_property(obj, sdi->sdi_data_strm, 0);
985 if (sdi->is_frac_prop)
986 drm_object_attach_property(obj, sdi->is_frac_prop, 0);
989 static int xilinx_sdi_create_connector(struct drm_encoder *encoder)
991 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
992 struct drm_connector *connector = &sdi->connector;
995 connector->polled = DRM_CONNECTOR_POLL_HPD;
996 connector->interlace_allowed = true;
997 connector->doublescan_allowed = true;
999 ret = drm_connector_init(encoder->dev, connector,
1000 &xilinx_sdi_connector_funcs,
1001 DRM_MODE_CONNECTOR_Unknown);
1003 dev_err(sdi->dev, "Failed to initialize connector with drm\n");
1007 drm_connector_helper_add(connector, &xilinx_sdi_connector_helper_funcs);
1008 drm_connector_register(connector);
1009 drm_mode_connector_attach_encoder(connector, encoder);
1010 xilinx_sdi_drm_connector_create_property(connector);
1011 xilinx_sdi_drm_connector_attach_property(connector);
1016 static bool xilinx_sdi_mode_fixup(struct drm_encoder *encoder,
1017 const struct drm_display_mode *mode,
1018 struct drm_display_mode *adjusted_mode)
1024 * xilinx_sdi_set_display_enable - Enables the SDI Tx IP core enable
1026 * @sdi: SDI structure having the updated user parameters
1028 * This function takes the SDI strucure and enables the core enable bit
1029 * of core configuration register.
1031 static void xilinx_sdi_set_display_enable(struct xilinx_sdi *sdi)
1035 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
1036 data |= XSDI_TX_CTRL_EN_MASK;
1037 /* start sdi stream */
1038 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
1041 static void xilinx_sdi_encoder_dpms(struct drm_encoder *encoder,
1044 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1046 dev_dbg(sdi->dev, "encoder dpms state: %d\n", mode);
1049 case DRM_MODE_DPMS_ON:
1050 xilinx_sdi_set_display_enable(sdi);
1053 xilinx_sdi_set_display_disable(sdi);
1054 xilinx_sdi_set_default_drm_properties(sdi);
1059 * xilinx_sdi_calc_st352_payld - calculate the st352 payload
1061 * @sdi: pointer to SDI Tx structure
1062 * @mode: DRM display mode
1064 * This function calculates the st352 payload to be configured.
1065 * Please refer to SMPTE ST352 documents for it.
1066 * Return: return st352 payload
1068 static u32 xilinx_sdi_calc_st352_payld(struct xilinx_sdi *sdi,
1069 struct drm_display_mode *mode)
1073 u32 id, sdi_mode = sdi->sdi_mod_prop_val;
1074 bool is_frac = sdi->is_frac_prop_val;
1075 u32 byt3 = ST352_BYTE3;
1077 id = xilinx_sdi_get_mode_id(mode);
1078 dev_dbg(sdi->dev, "mode id: %d\n", id);
1079 if (mode->hdisplay == 2048 || mode->hdisplay == 4096)
1080 byt3 |= XST352_2048_SHIFT;
1081 /* byte 2 calculation */
1082 is_p = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
1083 byt2 = xlnx_sdi_modes[id].st352_byt2[is_frac];
1084 if ((sdi_mode == XSDI_MODE_3GB) ||
1085 (mode->flags & DRM_MODE_FLAG_DBLSCAN) || is_p)
1086 byt2 |= XST352_PROG_PIC_MASK;
1087 if (is_p && (mode->vtotal >= 1125))
1088 byt2 |= XST352_PROG_TRANS_MASK;
1090 /* byte 1 calculation */
1091 byt1 = xlnx_sdi_modes[id].st352_byt1[sdi_mode];
1093 return (ST352_BYTE4 << 24 | byt3 << 16 | byt2 << 8 | byt1);
1097 * xilinx_sdi_mode_set - drive the SDI timing parameters
1099 * @encoder: pointer to Xilinx DRM encoder
1100 * @mode: DRM kernel-internal display mode structure
1101 * @adjusted_mode: SDI panel timing parameters
1103 * This function derives the SDI IP timing parameters from the timing
1104 * values given by VTC driver.
1106 static void xilinx_sdi_mode_set(struct drm_encoder *encoder,
1107 struct drm_display_mode *mode,
1108 struct drm_display_mode *adjusted_mode)
1110 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1111 struct videomode vm;
1114 xilinx_sdi_set_config_parameters(sdi);
1116 /* set st352 payloads */
1117 payload = xilinx_sdi_calc_st352_payld(sdi, adjusted_mode);
1118 dev_dbg(sdi->dev, "payload : %0x\n", payload);
1120 for (i = 0; i < sdi->sdi_data_strm_prop_val / 2; i++) {
1121 if (sdi->sdi_mod_prop_val == XSDI_MODE_3GB)
1122 payload |= (i << 1) << XSDI_CH_SHIFT;
1123 xilinx_sdi_set_payload_data(sdi, i, payload);
1126 /* UHDSDI is fixed 2 pixels per clock, horizontal timings div by 2 */
1127 vm.hactive = adjusted_mode->hdisplay / PIXELS_PER_CLK;
1128 vm.hfront_porch = (adjusted_mode->hsync_start -
1129 adjusted_mode->hdisplay) / PIXELS_PER_CLK;
1130 vm.hback_porch = (adjusted_mode->htotal -
1131 adjusted_mode->hsync_end) / PIXELS_PER_CLK;
1132 vm.hsync_len = (adjusted_mode->hsync_end -
1133 adjusted_mode->hsync_start) / PIXELS_PER_CLK;
1135 vm.vactive = adjusted_mode->vdisplay;
1136 vm.vfront_porch = adjusted_mode->vsync_start -
1137 adjusted_mode->vdisplay;
1138 vm.vback_porch = adjusted_mode->vtotal -
1139 adjusted_mode->vsync_end;
1140 vm.vsync_len = adjusted_mode->vsync_end -
1141 adjusted_mode->vsync_start;
1143 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
1144 vm.flags |= DISPLAY_FLAGS_INTERLACED;
1145 if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
1146 vm.flags |= DISPLAY_FLAGS_HSYNC_LOW;
1147 if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
1148 vm.flags |= DISPLAY_FLAGS_VSYNC_LOW;
1150 xilinx_vtc_config_sig(sdi->vtc, &vm);
1153 static void xilinx_sdi_prepare(struct drm_encoder *encoder)
1155 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1158 dev_dbg(sdi->dev, "%s\n", __func__);
1160 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
1161 reg |= XSDI_TX_CTRL_INS_CRC_MASK | XSDI_TX_CTRL_INS_ST352_MASK |
1162 XSDI_TX_CTRL_OVR_ST352_MASK | XSDI_TX_CTRL_INS_SYNC_BIT_MASK |
1163 XSDI_TX_CTRL_INS_EDH_MASK;
1164 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, reg);
1165 xilinx_sdi_writel(sdi->base, XSDI_TX_IER_STAT, XSDI_IER_EN_MASK);
1166 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 1);
1167 xilinx_vtc_reset(sdi->vtc);
1170 static void xilinx_sdi_commit(struct drm_encoder *encoder)
1172 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1175 dev_dbg(sdi->dev, "%s\n", __func__);
1176 xilinx_sdi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
1178 ret = wait_event_interruptible_timeout(sdi->wait_event,
1179 sdi->event_received,
1180 usecs_to_jiffies(GT_TIMEOUT));
1182 dev_err(sdi->dev, "Timeout: GT interrupt not received\n");
1185 sdi->event_received = false;
1186 /* enable sdi bridge, vtc and Axi4s_vid_out_ctrl */
1187 xilinx_en_bridge(sdi);
1188 xilinx_vtc_enable(sdi->vtc);
1189 xilinx_en_axi4s(sdi);
1192 static const struct drm_encoder_helper_funcs xilinx_sdi_encoder_helper_funcs = {
1193 .dpms = xilinx_sdi_encoder_dpms,
1194 .mode_fixup = xilinx_sdi_mode_fixup,
1195 .mode_set = xilinx_sdi_mode_set,
1196 .prepare = xilinx_sdi_prepare,
1197 .commit = xilinx_sdi_commit,
1200 static const struct drm_encoder_funcs xilinx_sdi_encoder_funcs = {
1201 .destroy = drm_encoder_cleanup,
1204 static int xilinx_sdi_bind(struct device *dev, struct device *master,
1207 struct xilinx_sdi *sdi = dev_get_drvdata(dev);
1208 struct drm_encoder *encoder = &sdi->encoder;
1209 struct drm_device *drm_dev = data;
1213 * TODO: The possible CRTCs are 1 now as per current implementation of
1214 * SDI tx drivers. DRM framework can support more than one CRTCs and
1215 * SDI driver can be enhanced for that.
1217 encoder->possible_crtcs = 1;
1219 drm_encoder_init(drm_dev, encoder, &xilinx_sdi_encoder_funcs,
1220 DRM_MODE_ENCODER_TMDS, NULL);
1222 drm_encoder_helper_add(encoder, &xilinx_sdi_encoder_helper_funcs);
1224 ret = xilinx_sdi_create_connector(encoder);
1226 dev_err(sdi->dev, "fail creating connector, ret = %d\n", ret);
1227 drm_encoder_cleanup(encoder);
1232 static void xilinx_sdi_unbind(struct device *dev, struct device *master,
1235 struct xilinx_sdi *sdi = dev_get_drvdata(dev);
1237 xilinx_sdi_encoder_dpms(&sdi->encoder, DRM_MODE_DPMS_OFF);
1238 drm_encoder_cleanup(&sdi->encoder);
1239 drm_connector_cleanup(&sdi->connector);
1242 static const struct component_ops xilinx_sdi_component_ops = {
1243 .bind = xilinx_sdi_bind,
1244 .unbind = xilinx_sdi_unbind,
1247 static irqreturn_t xilinx_sdi_vblank_handler(int irq, void *data)
1249 struct xilinx_sdi *sdi = (struct xilinx_sdi *)data;
1250 u32 intr = xilinx_vtc_intr_get(sdi->vtc);
1256 sdi->vblank_fn(sdi->vblank_data);
1258 xilinx_vtc_intr_clear(sdi->vtc, intr);
1263 * xilinx_drm_sdi_enable_vblank - Enable the vblank handling
1264 * @sdi: SDI subsystem
1265 * @vblank_fn: callback to be called on vblank event
1266 * @vblank_data: data to be used in @vblank_fn
1268 * This function register the vblank handler, and the handler will be triggered
1269 * on vblank event after.
1271 void xilinx_drm_sdi_enable_vblank(struct xilinx_sdi *sdi,
1272 void (*vblank_fn)(void *),
1275 sdi->vblank_fn = vblank_fn;
1276 sdi->vblank_data = vblank_data;
1277 xilinx_vtc_vblank_enable(sdi->vtc);
1279 EXPORT_SYMBOL_GPL(xilinx_drm_sdi_enable_vblank);
1282 * xilinx_drm_sdi_disable_vblank - Disable the vblank handling
1283 * @sdi: SDI subsystem
1285 * Disable the vblank handler. The vblank handler and data are unregistered.
1287 void xilinx_drm_sdi_disable_vblank(struct xilinx_sdi *sdi)
1289 sdi->vblank_fn = NULL;
1290 sdi->vblank_data = NULL;
1291 xilinx_vtc_vblank_disable(sdi->vtc);
1295 * xilinx_sdi_register_device - Register the SDI subsystem to the global list
1296 * @sdi: SDI subsystem
1298 * Register the SDI subsystem instance to the global list
1300 static void xilinx_sdi_register_device(struct xilinx_sdi *sdi)
1302 mutex_lock(&xilinx_sdi_lock);
1303 list_add_tail(&sdi->list, &xilinx_sdi_list);
1304 mutex_unlock(&xilinx_sdi_lock);
1308 * xilinx_drm_sdi_of_get - Get the SDI subsystem instance
1309 * @np: parent device node
1311 * This function searches and returns a SDI subsystem structure for
1312 * the parent device node, @np. The SDI subsystem node should be a child node
1313 * of @np, with 'xlnx,v-smpte-uhdsdi-tx-ss' property pointing to the SDI
1314 * device node. An instance can be shared by multiple users.
1316 * Return: corresponding SDI subsystem structure if found. NULL if
1317 * the device node doesn't have 'xlnx,v-smpte-uhdsdi-tx-ss' property, or
1318 * -EPROBE_DEFER error pointer if the the SDI subsystem isn't found.
1320 struct xilinx_sdi *xilinx_drm_sdi_of_get(struct device_node *np)
1322 struct xilinx_sdi *found = NULL;
1323 struct xilinx_sdi *sdi;
1324 struct device_node *ep_node, *sdi_node;
1326 ep_node = of_find_node_by_name(np, "endpoint");
1329 sdi_node = of_graph_get_remote_port_parent(ep_node);
1330 of_node_put(ep_node);
1334 mutex_lock(&xilinx_sdi_lock);
1335 list_for_each_entry(sdi, &xilinx_sdi_list, list) {
1336 if (sdi->dev->of_node == sdi_node) {
1341 mutex_unlock(&xilinx_sdi_lock);
1343 of_node_put(sdi_node);
1345 return ERR_PTR(-EPROBE_DEFER);
1350 * xilinx_sdi_unregister_device - Unregister the SDI subsystem instance
1351 * @sdi: SDI subsystem
1353 * Unregister the SDI subsystem instance from the global list
1355 static void xilinx_sdi_unregister_device(struct xilinx_sdi *sdi)
1357 mutex_lock(&xilinx_sdi_lock);
1358 list_del(&sdi->list);
1359 mutex_unlock(&xilinx_sdi_lock);
1362 static int xilinx_sdi_probe(struct platform_device *pdev)
1364 struct device *dev = &pdev->dev;
1365 struct resource *res;
1366 struct xilinx_sdi *sdi;
1367 struct device_node *vtc_node;
1370 sdi = devm_kzalloc(dev, sizeof(*sdi), GFP_KERNEL);
1375 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1376 sdi->base = devm_ioremap_resource(dev, res);
1378 if (IS_ERR(sdi->base)) {
1379 dev_err(dev, "failed to remap io region\n");
1380 return PTR_ERR(sdi->base);
1382 platform_set_drvdata(pdev, sdi);
1384 vtc_node = of_parse_phandle(sdi->dev->of_node, "xlnx,vtc", 0);
1386 dev_err(dev, "vtc node not present\n");
1387 return PTR_ERR(vtc_node);
1389 sdi->vtc = xilinx_vtc_probe(sdi->dev, vtc_node);
1390 of_node_put(vtc_node);
1391 if (IS_ERR(sdi->vtc)) {
1392 dev_err(dev, "failed to probe VTC\n");
1393 return PTR_ERR(sdi->vtc);
1396 /* disable interrupt */
1397 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 0);
1398 irq = platform_get_irq(pdev, 0);
1402 ret = devm_request_threaded_irq(sdi->dev, irq, NULL,
1403 xilinx_sdi_irq_handler, IRQF_ONESHOT,
1404 dev_name(sdi->dev), sdi);
1408 irq = platform_get_irq(pdev, 1); /* vblank interrupt */
1411 ret = devm_request_threaded_irq(sdi->dev, irq, NULL,
1412 xilinx_sdi_vblank_handler, IRQF_ONESHOT,
1413 "sdiTx-vblank", sdi);
1417 init_waitqueue_head(&sdi->wait_event);
1418 sdi->event_received = false;
1420 xilinx_sdi_register_device(sdi);
1421 return component_add(dev, &xilinx_sdi_component_ops);
1424 static int xilinx_sdi_remove(struct platform_device *pdev)
1426 struct xilinx_sdi *sdi = platform_get_drvdata(pdev);
1428 xilinx_sdi_unregister_device(sdi);
1429 component_del(&pdev->dev, &xilinx_sdi_component_ops);
1434 static const struct of_device_id xilinx_sdi_of_match[] = {
1435 { .compatible = "xlnx,v-smpte-uhdsdi-tx-ss"},
1438 MODULE_DEVICE_TABLE(of, xilinx_sdi_of_match);
1440 static struct platform_driver sdi_tx_driver = {
1441 .probe = xilinx_sdi_probe,
1442 .remove = xilinx_sdi_remove,
1444 .name = "xlnx,uhdsdi-tx",
1445 .of_match_table = xilinx_sdi_of_match,
1449 module_platform_driver(sdi_tx_driver);
1451 MODULE_AUTHOR("Saurabh Sengar <saurabhs@xilinx.com>");
1452 MODULE_DESCRIPTION("Xilinx FPGA SDI Tx Driver");
1453 MODULE_LICENSE("GPL v2");