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/of_device.h>
18 #include <linux/of_graph.h>
19 #include <linux/phy/phy.h>
20 #include <video/videomode.h>
21 #include "xilinx_vtc.h"
23 /* SDI register offsets */
24 #define XSDI_TX_RST_CTRL 0x00
25 #define XSDI_TX_MDL_CTRL 0x04
26 #define XSDI_TX_GLBL_IER 0x0C
27 #define XSDI_TX_ISR_STAT 0x10
28 #define XSDI_TX_IER_STAT 0x14
29 #define XSDI_TX_ST352_LINE 0x18
30 #define XSDI_TX_ST352_DATA_CH0 0x1C
31 #define XSDI_TX_VER 0x3C
32 #define XSDI_TX_SYS_CFG 0x40
33 #define XSDI_TX_STS_SB_TDATA 0x60
34 #define XSDI_TX_AXI4S_STS1 0x68
35 #define XSDI_TX_AXI4S_STS2 0x6C
37 /* MODULE_CTRL register masks */
38 #define XSDI_TX_CTRL_MDL_EN_MASK BIT(0)
39 #define XSDI_TX_CTRL_OUT_EN_MASK BIT(1)
40 #define XSDI_TX_CTRL_M_MASK BIT(7)
41 #define XSDI_TX_CTRL_INS_CRC_MASK BIT(12)
42 #define XSDI_TX_CTRL_INS_ST352_MASK BIT(13)
43 #define XSDI_TX_CTRL_OVR_ST352_MASK BIT(14)
44 #define XSDI_TX_CTRL_INS_SYNC_BIT_MASK BIT(16)
45 #define XSDI_TX_CTRL_SD_BITREP_BYPASS_MASK BIT(17)
46 #define XSDI_TX_CTRL_USE_ANC_IN_MASK BIT(18)
47 #define XSDI_TX_CTRL_INS_LN_MASK BIT(19)
48 #define XSDI_TX_CTRL_INS_EDH_MASK BIT(20)
49 #define XSDI_TX_CTRL_MODE_MASK 0x7
50 #define XSDI_TX_CTRL_MUX_MASK 0x7
51 #define XSDI_TX_CTRL_MODE_SHIFT 4
52 #define XSDI_TX_CTRL_M_SHIFT 7
53 #define XSDI_TX_CTRL_MUX_SHIFT 8
54 #define XSDI_TX_CTRL_INS_CRC_SHIFT 12
55 #define XSDI_TX_CTRL_INS_ST352_SHIFT 13
56 #define XSDI_TX_CTRL_OVR_ST352_SHIFT 14
57 #define XSDI_TX_CTRL_ST352_F2_EN_SHIFT 15
58 #define XSDI_TX_CTRL_INS_SYNC_BIT_SHIFT 16
59 #define XSDI_TX_CTRL_SD_BITREP_BYPASS_SHIFT 17
60 #define XSDI_TX_CTRL_USE_ANC_IN_SHIFT 18
61 #define XSDI_TX_CTRL_INS_LN_SHIFT 19
62 #define XSDI_TX_CTRL_INS_EDH_SHIFT 20
64 /* TX_ST352_LINE register masks */
65 #define XSDI_TX_ST352_LINE_MASK GENMASK(10, 0)
66 #define XSDI_TX_ST352_LINE_F2_SHIFT 16
68 /* ISR STAT register masks */
69 #define XSDI_GTTX_RSTDONE_INTR_MASK BIT(0)
70 #define XSDI_TX_CE_ALIGN_ERR_INTR_MASK BIT(1)
71 #define XSDI_AXI4S_VID_LOCK_INTR_MASK BIT(8)
72 #define XSDI_OVERFLOW_INTR_MASK BIT(9)
73 #define XSDI_UNDERFLOW_INTR_MASK BIT(10)
74 #define XSDI_IER_EN_MASK (XSDI_GTTX_RSTDONE_INTR_MASK | \
75 XSDI_TX_CE_ALIGN_ERR_INTR_MASK | \
76 XSDI_OVERFLOW_INTR_MASK | \
77 XSDI_UNDERFLOW_INTR_MASK)
79 /* RST_CTRL_OFFSET masks */
80 #define XSDI_TX_BRIDGE_CTRL_EN_MASK BIT(8)
81 #define XSDI_TX_AXI4S_CTRL_EN_MASK BIT(9)
82 #define XSDI_TX_CTRL_EN_MASK BIT(0)
84 /* STS_SB_TX_TDATA masks */
85 #define XSDI_TX_TDATA_DONE_MASK BIT(0)
86 #define XSDI_TX_TDATA_FAIL_MASK BIT(1)
87 #define XSDI_TX_TDATA_GT_RESETDONE_MASK BIT(2)
88 #define XSDI_TX_TDATA_SLEW_RATE_MASK BIT(3)
89 #define XSDI_TX_TDATA_TXPLLCLKSEL_MASK GENMASK(5, 4)
90 #define XSDI_TX_TDATA_GT_SYSCLKSEL_MASK GENMASK(7, 6)
91 #define XSDI_TX_TDATA_FABRIC_RST_MASK BIT(8)
92 #define XSDI_TX_TDATA_DRP_FAIL_MASK BIT(9)
93 #define XSDI_TX_TDATA_FAIL_CODE_MASK GENMASK(14, 12)
94 #define XSDI_TX_TDATA_DRP_FAIL_CNT_MASK 0xFF0000
95 #define XSDI_TX_TDATA_GT_QPLL0LOCK_MASK BIT(24)
96 #define XSDI_TX_TDATA_GT_QPLL1LOCK_MASK BIT(25)
98 #define SDI_MAX_DATASTREAM 8
100 #define XSDI_TX_MUX_SD_HD_3GA 0
101 #define XSDI_TX_MUX_3GB 1
102 #define XSDI_TX_MUX_8STREAM_6G_12G 2
103 #define XSDI_TX_MUX_4STREAM_6G 3
104 #define XSDI_TX_MUX_16STREAM_12G 4
106 #define PIXELS_PER_CLK 2
107 #define XSDI_CH_SHIFT 29
108 #define XST352_PROG_SHIFT 6
109 #define XST352_TRANS_SHIFT 7
110 #define XST352_2048_SHIFT BIT(6)
111 #define XST352_PSF_MODE BIT(6)
112 #define ST352_BYTE3 0x00
113 #define ST352_BYTE4 0x01
114 #define INVALID_VALUE -1
115 #define GT_TIMEOUT 500
117 * enum payload_line_1 - Payload Ids Line 1 number
118 * @PAYLD_LN1_HD_3_6_12G: line 1 HD,3G,6G or 12G mode value
119 * @PAYLD_LN1_SDPAL: line 1 SD PAL mode value
120 * @PAYLD_LN1_SDNTSC: line 1 SD NTSC mode value
122 enum payload_line_1 {
123 PAYLD_LN1_HD_3_6_12G = 10,
125 PAYLD_LN1_SDNTSC = 13
129 * enum payload_line_2 - Payload Ids Line 2 number
130 * @PAYLD_LN2_HD_3_6_12G: line 2 HD,3G,6G or 12G mode value
131 * @PAYLD_LN2_SDPAL: line 2 SD PAL mode value
132 * @PAYLD_LN2_SDNTSC: line 2 SD NTSC mode value
134 enum payload_line_2 {
135 PAYLD_LN2_HD_3_6_12G = 572,
136 PAYLD_LN2_SDPAL = 322,
137 PAYLD_LN2_SDNTSC = 276
141 * enum sdi_modes - SDI modes
142 * @XSDI_MODE_HD: HD mode
143 * @XSDI_MODE_SD: SD mode
144 * @XSDI_MODE_3GA: 3GA mode
145 * @XSDI_MODE_3GB: 3GB mode
146 * @XSDI_MODE_6G: 6G mode
147 * @XSDI_MODE_12G: 12G mode
159 * struct xilinx_sdi - Core configuration SDI Tx subsystem device structure
160 * @encoder: DRM encoder structure
161 * @connector: DRM connector structure
162 * @vtc: Pointer to VTC structure
163 * @dev: device structure
164 * @base: Base address of SDI subsystem
165 * @mode_flags: SDI operation mode related flags
166 * @wait_event: wait event
167 * @event_received: wait event status
168 * @sdi_mode: configurable SDI mode parameter, supported values are:
175 * @sdi_mod_prop_val: configurable SDI mode parameter value
176 * @sdi_data_strm: configurable SDI data stream parameter
177 * @sdi_data_strm_prop_val: configurable number of SDI data streams
178 * value currently supported are 2, 4 and 8
179 * @is_frac_prop: configurable SDI fractional fps parameter
180 * @is_frac_prop_val: configurable SDI fractional fps parameter value
183 struct drm_encoder encoder;
184 struct drm_connector connector;
185 struct xilinx_vtc *vtc;
189 wait_queue_head_t wait_event;
191 struct drm_property *sdi_mode;
192 u32 sdi_mod_prop_val;
193 struct drm_property *sdi_data_strm;
194 u32 sdi_data_strm_prop_val;
195 struct drm_property *is_frac_prop;
196 bool is_frac_prop_val;
200 * struct xilinx_sdi_display_config - SDI supported modes structure
201 * @mode: drm display mode
202 * @st352_byt2: st352 byte 2 value
203 * index 0 : value for integral fps
204 * index 1 : value for fractional fps
205 * @st352_byt1: st352 byte 1 value
206 * index 0 : value for HD mode
207 * index 1 : value for SD mode
208 * index 2 : value for 3GA
209 * index 3 : value for 3GB
210 * index 4 : value for 6G
211 * index 5 : value for 12G
213 struct xlnx_sdi_display_config {
214 struct drm_display_mode mode;
220 * xlnx_sdi_modes - SDI DRM modes
222 static const struct xlnx_sdi_display_config xlnx_sdi_modes[] = {
223 /* 0 - dummy, VICs start at 1 */
225 /* SD: 720x480i@60Hz */
226 {{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
227 801, 858, 0, 240, 244, 247, 262, 0,
228 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
229 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
230 .vrefresh = 60, }, {0x7, 0x6},
231 {0x81, 0x81, 0x81, 0x81, 0x81, 0x81} },
232 /* SD: 720x576i@50Hz */
233 {{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
234 795, 864, 0, 288, 290, 293, 312, 0,
235 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
236 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
237 .vrefresh = 50, }, {0x9, 0x9},
238 {0x81, 0x81, 0x81, 0x81, 0x81, 0x81} },
239 /* HD: 1280x720@25Hz */
240 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
241 2990, 3960, 0, 720, 725, 730, 750, 0,
242 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
243 .vrefresh = 25, }, {0x5, 0x5},
244 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
245 /* HD: 1280x720@24Hz */
246 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
247 3155, 4125, 0, 720, 725, 730, 750, 0,
248 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
249 .vrefresh = 24, }, {0x3, 0x2},
250 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
251 /* HD: 1280x720@30Hz */
252 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
253 2330, 3300, 0, 720, 725, 730, 750, 0,
254 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
255 .vrefresh = 30, }, {0x7, 0x6},
256 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
257 /* HD: 1280x720@50Hz */
258 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
259 1760, 1980, 0, 720, 725, 730, 750, 0,
260 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
261 .vrefresh = 50, }, {0x9, 0x9},
262 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
263 /* HD: 1280x720@60Hz */
264 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
265 1430, 1650, 0, 720, 725, 730, 750, 0,
266 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
267 .vrefresh = 60, }, {0xB, 0xA},
268 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
269 /* HD: 1920x1080@24Hz */
270 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
271 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
272 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
273 .vrefresh = 24, }, {0x3, 0x2},
274 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
275 /* HD: 1920x1080@25Hz */
276 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
277 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
278 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
279 .vrefresh = 25, }, {0x5, 0x5},
280 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
281 /* HD: 1920x1080@30Hz */
282 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
283 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
284 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
285 .vrefresh = 30, }, {0x7, 0x6},
286 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
287 /* HD: 1920x1080i@48Hz */
288 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2291,
289 2379, 2750, 0, 540, 542, 547, 562, 0,
290 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
291 DRM_MODE_FLAG_INTERLACE),
292 .vrefresh = 48, }, {0x3, 0x2},
293 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
294 /* HD: 1920x1080i@50Hz */
295 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
296 2492, 2640, 0, 540, 542, 547, 562, 0,
297 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
298 DRM_MODE_FLAG_INTERLACE),
299 .vrefresh = 50, }, {0x5, 0x5},
300 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
301 /* HD: 1920x1080i@60Hz */
302 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
303 2052, 2200, 0, 540, 542, 547, 562, 0,
304 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
305 DRM_MODE_FLAG_INTERLACE),
306 .vrefresh = 60, }, {0x7, 0x6},
307 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
308 /* HD: 2048x1080i@48Hz */
309 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2377,
310 2421, 2750, 0, 540, 542, 547, 562, 0,
311 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
312 DRM_MODE_FLAG_INTERLACE),
313 .vrefresh = 48, }, {0x3, 0x2},
314 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
315 /* HD: 2048x1080i@50Hz */
316 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2322,
317 2366, 2640, 0, 540, 542, 547, 562, 0,
318 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
319 DRM_MODE_FLAG_INTERLACE),
320 .vrefresh = 50, }, {0x5, 0x5},
321 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
322 /* HD: 2048x1080i@60Hz */
323 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2114,
324 2134, 2200, 0, 540, 542, 547, 562, 0,
325 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
326 DRM_MODE_FLAG_INTERLACE),
327 .vrefresh = 60, }, {0x7, 0x6},
328 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
329 /* HD: 2048x1080@30Hz */
330 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2114,
331 2134, 2200, 0, 1080, 1084, 1089, 1125, 0,
332 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
333 .vrefresh = 30, }, {0x7, 0x6},
334 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
335 /* HD: 2048x1080@25Hz */
336 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2448,
337 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
338 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
339 .vrefresh = 25, }, {0x5, 0x5},
340 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
341 /* HD: 2048x1080@24Hz */
342 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2558,
343 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
344 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
345 .vrefresh = 24, }, {0x3, 0x2},
346 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
347 /* 3G: 1920x1080@48Hz */
348 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2558,
349 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
350 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
351 .vrefresh = 48, }, {0x8, 0x4},
352 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
353 /* 3G: 1920x1080@50Hz */
354 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
355 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
356 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
357 .vrefresh = 50, }, {0x9, 0x9},
358 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
359 /* 3G: 1920x1080@60Hz */
360 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
361 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
362 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
363 .vrefresh = 60, }, {0xB, 0xA},
364 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
365 /* 3G: 2048x1080@60Hz */
366 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2136,
367 2180, 2200, 0, 1080, 1084, 1089, 1125, 0,
368 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
369 .vrefresh = 60, }, {0xB, 0xA},
370 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
371 /* 3G: 2048x1080@50Hz */
372 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2448,
373 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
374 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
375 .vrefresh = 50, }, {0x9, 0x9},
376 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
377 /* 3G: 2048x1080@48Hz */
378 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2558,
379 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
380 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
381 .vrefresh = 48, }, {0x8, 0x4},
382 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
383 /* 3G-B: 1920x1080i@96Hz */
384 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2291,
385 2379, 2750, 0, 1080, 1084, 1094, 1124, 0,
386 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
387 DRM_MODE_FLAG_INTERLACE),
388 .vrefresh = 96, }, {0x8, 0x4},
389 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
390 /* 3G-B: 1920x1080i@100Hz */
391 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
392 2492, 2640, 0, 1080, 1084, 1094, 1124, 0,
393 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
394 DRM_MODE_FLAG_INTERLACE),
395 .vrefresh = 100, }, {0x9, 0x9},
396 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
397 /* 3G-B: 1920x1080i@120Hz */
398 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
399 2052, 2200, 0, 1080, 1084, 1094, 1124, 0,
400 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
401 DRM_MODE_FLAG_INTERLACE),
402 .vrefresh = 120, }, {0xB, 0xA},
403 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
404 /* 3G-B: 2048x1080i@96Hz */
405 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2377,
406 2421, 2750, 0, 1080, 1084, 1094, 1124, 0,
407 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
408 DRM_MODE_FLAG_INTERLACE),
409 .vrefresh = 96, }, {0x8, 0x4},
410 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
411 /* 3G-B: 2048x1080i@100Hz */
412 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2322,
413 2366, 2640, 0, 1080, 1084, 1094, 1124, 0,
414 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
415 DRM_MODE_FLAG_INTERLACE),
416 .vrefresh = 100, }, {0x9, 0x9},
417 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
418 /* 3G-B: 2048x1080i@120Hz */
419 {{ DRM_MODE("2048x1080i", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2114,
420 2134, 2200, 0, 1080, 1084, 1094, 1124, 0,
421 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
422 DRM_MODE_FLAG_INTERLACE),
423 .vrefresh = 120, }, {0xB, 0xA},
424 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
425 /* 6G: 3840x2160@30Hz */
426 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
427 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
428 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
429 .vrefresh = 30, }, {0x7, 0x6},
430 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
431 /* 6G: 3840x2160@25Hz */
432 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896,
433 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
434 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
435 .vrefresh = 25, }, {0x5, 0x5},
436 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
437 /* 6G: 3840x2160@24Hz */
438 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
439 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
440 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
441 .vrefresh = 24, }, {0x3, 0x2},
442 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
443 /* 6G: 4096x2160@24Hz */
444 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 296704, 4096, 5116,
445 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
446 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
447 .vrefresh = 24, }, {0x3, 0x2},
448 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
449 /* 6G: 4096x2160@25Hz */
450 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064,
451 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
452 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
453 .vrefresh = 25, }, {0x5, 0x5},
454 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
455 /* 6G: 4096x2160@30Hz */
456 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 296704, 4096, 4184,
457 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
458 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
459 .vrefresh = 30, }, {0x7, 0x6},
460 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
461 /* 12G: 3840x2160@48Hz */
462 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 5116,
463 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
464 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
465 .vrefresh = 48, }, {0x8, 0x4},
466 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
467 /* 12G: 3840x2160@50Hz */
468 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
469 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
470 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
471 .vrefresh = 50, }, {0x9, 0x9},
472 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
473 /* 12G: 3840x2160@60Hz */
474 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
475 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
476 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
477 .vrefresh = 60, }, {0xB, 0xA},
478 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
479 /* 12G: 4096x2160@48Hz */
480 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5116,
481 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
482 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
483 .vrefresh = 48, }, {0x8, 0x4},
484 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
485 /* 12G: 4096x2160@50Hz */
486 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064,
487 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
488 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
489 .vrefresh = 50, }, {0x9, 0x9},
490 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
491 /* 12G: 4096x2160@60Hz */
492 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 593408, 4096, 4184,
493 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
494 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
495 .vrefresh = 60, }, {0xB, 0xA},
496 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
499 #define connector_to_sdi(c) container_of(c, struct xilinx_sdi, connector)
500 #define encoder_to_sdi(e) container_of(e, struct xilinx_sdi, encoder)
503 * xilinx_sdi_writel - Memory mapped SDI Tx register write
504 * @base: Pointer to SDI Tx registers base
505 * @offset: Register offset
506 * @val: value to be written
508 * This function writes the value to SDI TX registers
510 static inline void xilinx_sdi_writel(void __iomem *base, int offset, u32 val)
512 writel(val, base + offset);
516 * xilinx_sdi_readl - Memory mapped SDI Tx register read
517 * @base: Pointer to SDI Tx registers base
518 * @offset: Register offset
520 * Return: The contents of the SDI Tx register
522 * This function returns the contents of the corresponding SDI Tx register.
524 static inline u32 xilinx_sdi_readl(void __iomem *base, int offset)
526 return readl(base + offset);
530 * xilinx_en_axi4s - Enable SDI Tx AXI4S-to-Video core
531 * @sdi: Pointer to SDI Tx structure
533 * This function enables the SDI Tx AXI4S-to-Video core.
535 static void xilinx_en_axi4s(struct xilinx_sdi *sdi)
539 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
540 data |= XSDI_TX_AXI4S_CTRL_EN_MASK;
541 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
545 * xilinx_en_bridge - Enable SDI Tx bridge
546 * @sdi: Pointer to SDI Tx structure
548 * This function enables the SDI Tx bridge.
550 static void xilinx_en_bridge(struct xilinx_sdi *sdi)
554 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
555 data |= XSDI_TX_BRIDGE_CTRL_EN_MASK;
556 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
560 * xilinx_sdi_set_default_drm_properties - Configure SDI DRM
561 * properties with their default values
562 * @sdi: SDI structure having the updated user parameters
565 xilinx_sdi_set_default_drm_properties(struct xilinx_sdi *sdi)
567 drm_object_property_set_value(&sdi->connector.base,
569 drm_object_property_set_value(&sdi->connector.base,
570 sdi->sdi_data_strm, 0);
571 drm_object_property_set_value(&sdi->connector.base,
572 sdi->is_frac_prop, 0);
576 * xilinx_sdi_irq_handler - SDI Tx interrupt
580 * Return: IRQ_HANDLED for all cases.
582 * This is the compact GT ready interrupt.
584 static irqreturn_t xilinx_sdi_irq_handler(int irq, void *data)
586 struct xilinx_sdi *sdi = (struct xilinx_sdi *)data;
589 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_ISR_STAT);
591 if (reg & XSDI_GTTX_RSTDONE_INTR_MASK)
592 dev_dbg(sdi->dev, "GT reset interrupt received\n");
593 if (reg & XSDI_TX_CE_ALIGN_ERR_INTR_MASK)
594 dev_err_ratelimited(sdi->dev, "SDI SD CE align error\n");
595 if (reg & XSDI_OVERFLOW_INTR_MASK)
596 dev_err_ratelimited(sdi->dev, "AXI-4 Stream Overflow error\n");
597 if (reg & XSDI_UNDERFLOW_INTR_MASK)
598 dev_err_ratelimited(sdi->dev, "AXI-4 Stream Underflow error\n");
599 xilinx_sdi_writel(sdi->base, XSDI_TX_ISR_STAT,
600 reg & ~(XSDI_AXI4S_VID_LOCK_INTR_MASK));
602 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_STS_SB_TDATA);
603 if (reg & XSDI_TX_TDATA_GT_RESETDONE_MASK) {
604 sdi->event_received = true;
605 wake_up_interruptible(&sdi->wait_event);
611 * xilinx_sdi_set_payload_line - set ST352 packet line number
612 * @sdi: Pointer to SDI Tx structure
613 * @line_1: line number used to insert st352 packet for field 1.
614 * @line_2: line number used to insert st352 packet for field 2.
616 * This function set 352 packet line number.
618 static void xilinx_sdi_set_payload_line(struct xilinx_sdi *sdi,
619 u32 line_1, u32 line_2)
623 data = ((line_1 & XSDI_TX_ST352_LINE_MASK) |
624 ((line_2 & XSDI_TX_ST352_LINE_MASK) <<
625 XSDI_TX_ST352_LINE_F2_SHIFT));
627 xilinx_sdi_writel(sdi->base, XSDI_TX_ST352_LINE, data);
629 data = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
630 data |= (1 << XSDI_TX_CTRL_ST352_F2_EN_SHIFT);
632 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, data);
636 * xilinx_sdi_set_payload_data - set ST352 packet payload
637 * @sdi: Pointer to SDI Tx structure
638 * @data_strm: data stream number
639 * @payload: st352 packet payload
641 * This function set ST352 payload data to corresponding stream.
643 static void xilinx_sdi_set_payload_data(struct xilinx_sdi *sdi,
644 u32 data_strm, u32 payload)
646 xilinx_sdi_writel(sdi->base,
647 (XSDI_TX_ST352_DATA_CH0 + (data_strm * 4)), payload);
651 * xilinx_sdi_set_display_disable - Disable the SDI Tx IP core enable
653 * @sdi: SDI structure having the updated user parameters
655 * This function takes the SDI strucure and disables the core enable bit
656 * of core configuration register.
658 static void xilinx_sdi_set_display_disable(struct xilinx_sdi *sdi)
662 for (i = 0; i < SDI_MAX_DATASTREAM; i++)
663 xilinx_sdi_set_payload_data(sdi, i, 0);
665 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 0);
666 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, 0);
670 * xilinx_sdi_payload_config - config the SDI payload parameters
671 * @sdi: pointer Xilinx SDI Tx structure
672 * @mode: display mode
674 * This function config the SDI st352 payload parameter.
676 static void xilinx_sdi_payload_config(struct xilinx_sdi *sdi, u32 mode)
678 u32 payload_1, payload_2;
682 payload_1 = PAYLD_LN1_SDPAL;
683 payload_2 = PAYLD_LN2_SDPAL;
690 payload_1 = PAYLD_LN1_HD_3_6_12G;
691 payload_2 = PAYLD_LN2_HD_3_6_12G;
699 xilinx_sdi_set_payload_line(sdi, payload_1, payload_2);
703 * xilinx_set_sdi_mode - Set mode parameters in SDI Tx
704 * @sdi: pointer Xilinx SDI Tx structure
705 * @mode: SDI Tx display mode
706 * @is_frac: 0 - integer 1 - fractional
707 * @mux_ptrn: specifiy the data stream interleaving pattern to be used
708 * This function config the SDI st352 payload parameter.
710 static void xilinx_set_sdi_mode(struct xilinx_sdi *sdi, u32 mode,
711 bool is_frac, u32 mux_ptrn)
715 xilinx_sdi_payload_config(sdi, mode);
717 data = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
718 data &= ~((XSDI_TX_CTRL_MODE_MASK << XSDI_TX_CTRL_MODE_SHIFT) |
719 (XSDI_TX_CTRL_M_MASK) | (XSDI_TX_CTRL_MUX_MASK
720 << XSDI_TX_CTRL_MUX_SHIFT));
722 data |= (((mode & XSDI_TX_CTRL_MODE_MASK)
723 << XSDI_TX_CTRL_MODE_SHIFT) |
724 (is_frac << XSDI_TX_CTRL_M_SHIFT) |
725 ((mux_ptrn & XSDI_TX_CTRL_MUX_MASK) << XSDI_TX_CTRL_MUX_SHIFT));
727 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, data);
731 * xilinx_sdi_set_config_parameters - Configure SDI Tx registers with parameters
732 * given from user application.
733 * @sdi: SDI structure having the updated user parameters
735 * This function takes the SDI structure having drm_property parameters
736 * configured from user application and writes them into SDI IP registers.
738 static void xilinx_sdi_set_config_parameters(struct xilinx_sdi *sdi)
741 int mux_ptrn = INVALID_VALUE;
744 mode = sdi->sdi_mod_prop_val;
745 is_frac = sdi->is_frac_prop_val;
749 mux_ptrn = XSDI_TX_MUX_SD_HD_3GA;
752 mux_ptrn = XSDI_TX_MUX_3GB;
755 if (sdi->sdi_data_strm_prop_val == 4)
756 mux_ptrn = XSDI_TX_MUX_4STREAM_6G;
757 else if (sdi->sdi_data_strm_prop_val == 8)
758 mux_ptrn = XSDI_TX_MUX_8STREAM_6G_12G;
761 if (sdi->sdi_data_strm_prop_val == 8)
762 mux_ptrn = XSDI_TX_MUX_8STREAM_6G_12G;
768 if (mux_ptrn == INVALID_VALUE) {
769 dev_err(sdi->dev, "%d data stream not supported for %d mode",
770 sdi->sdi_data_strm_prop_val, mode);
773 xilinx_set_sdi_mode(sdi, mode, is_frac, mux_ptrn);
777 * xilinx_sdi_connector_set_property - implementation of drm_connector_funcs
778 * set_property invoked by IOCTL call to DRM_IOCTL_MODE_OBJ_SETPROPERTY
780 * @base_connector: pointer Xilinx SDI connector
781 * @property: pointer to the drm_property structure
782 * @value: SDI parameter value that is configured from user application
784 * This function takes a drm_property name and value given from user application
785 * and update the SDI structure property varabiles with the values.
786 * These values are later used to configure the SDI Rx IP.
788 * Return: 0 on success OR -EINVAL if setting property fails
791 xilinx_sdi_connector_set_property(struct drm_connector *base_connector,
792 struct drm_property *property,
795 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
797 if (property == sdi->sdi_mode)
798 sdi->sdi_mod_prop_val = (unsigned int)value;
799 else if (property == sdi->sdi_data_strm)
800 sdi->sdi_data_strm_prop_val = (unsigned int)value;
801 else if (property == sdi->is_frac_prop)
802 sdi->is_frac_prop_val = !!value;
809 * xilinx_sdi_get_mode_id - Search for a video mode in the supported modes table
811 * @mode: mode being searched
813 * Return: true if mode is found
815 static int xilinx_sdi_get_mode_id(struct drm_display_mode *mode)
819 for (i = 0; i < ARRAY_SIZE(xlnx_sdi_modes); i++)
820 if (drm_mode_equal(&xlnx_sdi_modes[i].mode, mode))
826 * xilinx_sdi_drm_add_modes - Adds SDI supported modes
827 * @connector: pointer Xilinx SDI connector
829 * Return: Count of modes added
831 * This function adds the SDI modes supported and returns its count
833 static int xilinx_sdi_drm_add_modes(struct drm_connector *connector)
835 int i, num_modes = 0;
836 struct drm_display_mode *mode;
837 struct drm_device *dev = connector->dev;
839 for (i = 0; i < ARRAY_SIZE(xlnx_sdi_modes); i++) {
840 const struct drm_display_mode *ptr = &xlnx_sdi_modes[i].mode;
842 mode = drm_mode_duplicate(dev, ptr);
844 drm_mode_probed_add(connector, mode);
851 static int xilinx_sdi_connector_dpms(struct drm_connector *connector,
854 return drm_helper_connector_dpms(connector, mode);
857 static enum drm_connector_status
858 xilinx_sdi_detect(struct drm_connector *connector, bool force)
860 return connector_status_connected;
863 static void xilinx_sdi_connector_destroy(struct drm_connector *connector)
865 drm_connector_unregister(connector);
866 drm_connector_cleanup(connector);
867 connector->dev = NULL;
870 static const struct drm_connector_funcs xilinx_sdi_connector_funcs = {
871 .dpms = xilinx_sdi_connector_dpms,
872 .detect = xilinx_sdi_detect,
873 .fill_modes = drm_helper_probe_single_connector_modes,
874 .destroy = xilinx_sdi_connector_destroy,
875 .set_property = xilinx_sdi_connector_set_property,
878 static struct drm_encoder *
879 xilinx_sdi_best_encoder(struct drm_connector *connector)
881 return &(connector_to_sdi(connector)->encoder);
884 static int xilinx_sdi_get_modes(struct drm_connector *connector)
886 return xilinx_sdi_drm_add_modes(connector);
889 static struct drm_connector_helper_funcs xilinx_sdi_connector_helper_funcs = {
890 .get_modes = xilinx_sdi_get_modes,
891 .best_encoder = xilinx_sdi_best_encoder,
895 * xilinx_sdi_drm_connector_create_property - create SDI connector properties
897 * @base_connector: pointer to Xilinx SDI connector
899 * This function takes the xilinx SDI connector component and defines
900 * the drm_property variables with their default values.
903 xilinx_sdi_drm_connector_create_property(struct drm_connector *base_connector)
905 struct drm_device *dev = base_connector->dev;
906 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
908 sdi->is_frac_prop = drm_property_create_bool(dev, 1, "is_frac");
909 sdi->sdi_mode = drm_property_create_range(dev, 0,
911 sdi->sdi_data_strm = drm_property_create_range(dev, 0,
912 "sdi_data_stream", 2, 8);
916 * xilinx_sdi_drm_connector_attach_property - attach SDI connector
919 * @base_connector: pointer to Xilinx SDI connector
922 xilinx_sdi_drm_connector_attach_property(struct drm_connector *base_connector)
924 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
925 struct drm_mode_object *obj = &base_connector->base;
928 drm_object_attach_property(obj, sdi->sdi_mode, 0);
930 if (sdi->sdi_data_strm)
931 drm_object_attach_property(obj, sdi->sdi_data_strm, 0);
933 if (sdi->is_frac_prop)
934 drm_object_attach_property(obj, sdi->is_frac_prop, 0);
937 static int xilinx_sdi_create_connector(struct drm_encoder *encoder)
939 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
940 struct drm_connector *connector = &sdi->connector;
943 connector->polled = DRM_CONNECTOR_POLL_HPD;
944 connector->interlace_allowed = true;
946 ret = drm_connector_init(encoder->dev, connector,
947 &xilinx_sdi_connector_funcs,
948 DRM_MODE_CONNECTOR_Unknown);
950 dev_err(sdi->dev, "Failed to initialize connector with drm\n");
954 drm_connector_helper_add(connector, &xilinx_sdi_connector_helper_funcs);
955 drm_connector_register(connector);
956 drm_mode_connector_attach_encoder(connector, encoder);
957 xilinx_sdi_drm_connector_create_property(connector);
958 xilinx_sdi_drm_connector_attach_property(connector);
963 static bool xilinx_sdi_mode_fixup(struct drm_encoder *encoder,
964 const struct drm_display_mode *mode,
965 struct drm_display_mode *adjusted_mode)
971 * xilinx_sdi_set_display_enable - Enables the SDI Tx IP core enable
973 * @sdi: SDI structure having the updated user parameters
975 * This function takes the SDI strucure and enables the core enable bit
976 * of core configuration register.
978 static void xilinx_sdi_set_display_enable(struct xilinx_sdi *sdi)
982 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
983 data |= XSDI_TX_CTRL_EN_MASK;
984 /* start sdi stream */
985 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
988 static void xilinx_sdi_encoder_dpms(struct drm_encoder *encoder,
991 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
993 dev_dbg(sdi->dev, "encoder dpms state: %d\n", mode);
996 case DRM_MODE_DPMS_ON:
997 xilinx_sdi_set_display_enable(sdi);
1000 xilinx_sdi_set_display_disable(sdi);
1001 xilinx_sdi_set_default_drm_properties(sdi);
1006 * xilinx_sdi_calc_st352_payld - calculate the st352 payload
1008 * @sdi: pointer to SDI Tx structure
1009 * @mode: DRM display mode
1011 * This function calculates the st352 payload to be configured.
1012 * Please refer to SMPTE ST352 documents for it.
1013 * Return: return st352 payload
1015 static u32 xilinx_sdi_calc_st352_payld(struct xilinx_sdi *sdi,
1016 struct drm_display_mode *mode)
1020 u32 id, sdi_mode = sdi->sdi_mod_prop_val;
1021 bool is_frac = sdi->is_frac_prop_val;
1022 u32 byt3 = ST352_BYTE3;
1024 id = xilinx_sdi_get_mode_id(mode);
1025 dev_dbg(sdi->dev, "mode id: %d\n", id);
1026 if (mode->hdisplay == 2048 || mode->hdisplay == 4096)
1027 byt3 |= XST352_2048_SHIFT;
1028 /* byte 2 calculation */
1029 is_p = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
1030 smpl_r = xlnx_sdi_modes[id].st352_byt2[is_frac];
1031 if (sdi_mode == XSDI_MODE_3GB) {
1032 byt2 = XST352_PSF_MODE | smpl_r;
1034 byt2 = (is_p << XST352_PROG_SHIFT) | smpl_r;
1035 if (mode->vtotal >= 1125)
1036 byt2 |= (is_p << XST352_TRANS_SHIFT);
1038 /* byte 1 calculation */
1039 byt1 = xlnx_sdi_modes[id].st352_byt1[sdi_mode];
1041 return (ST352_BYTE4 << 24 | byt3 << 16 | byt2 << 8 | byt1);
1045 * xilinx_sdi_mode_set - drive the SDI timing parameters
1047 * @encoder: pointer to Xilinx DRM encoder
1048 * @mode: DRM kernel-internal display mode structure
1049 * @adjusted_mode: SDI panel timing parameters
1051 * This function derives the SDI IP timing parameters from the timing
1052 * values given by VTC driver.
1054 static void xilinx_sdi_mode_set(struct drm_encoder *encoder,
1055 struct drm_display_mode *mode,
1056 struct drm_display_mode *adjusted_mode)
1058 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1059 struct videomode vm;
1062 xilinx_sdi_set_config_parameters(sdi);
1064 /* set st352 payloads */
1065 payload = xilinx_sdi_calc_st352_payld(sdi, adjusted_mode);
1066 dev_dbg(sdi->dev, "payload : %0x\n", payload);
1068 for (i = 0; i < sdi->sdi_data_strm_prop_val / 2; i++) {
1069 if (sdi->sdi_mod_prop_val == XSDI_MODE_3GB)
1070 payload |= (i << 1) << XSDI_CH_SHIFT;
1071 xilinx_sdi_set_payload_data(sdi, i, payload);
1074 /* UHDSDI is fixed 2 pixels per clock, horizontal timings div by 2 */
1075 vm.hactive = adjusted_mode->hdisplay / PIXELS_PER_CLK;
1076 vm.hfront_porch = (adjusted_mode->hsync_start -
1077 adjusted_mode->hdisplay) / PIXELS_PER_CLK;
1078 vm.hback_porch = (adjusted_mode->htotal -
1079 adjusted_mode->hsync_end) / PIXELS_PER_CLK;
1080 vm.hsync_len = (adjusted_mode->hsync_end -
1081 adjusted_mode->hsync_start) / PIXELS_PER_CLK;
1083 vm.vactive = adjusted_mode->vdisplay;
1084 vm.vfront_porch = adjusted_mode->vsync_start -
1085 adjusted_mode->vdisplay;
1086 vm.vback_porch = adjusted_mode->vtotal -
1087 adjusted_mode->vsync_end;
1088 vm.vsync_len = adjusted_mode->vsync_end -
1089 adjusted_mode->vsync_start;
1091 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
1092 vm.flags |= DISPLAY_FLAGS_INTERLACED;
1093 if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
1094 vm.flags |= DISPLAY_FLAGS_HSYNC_LOW;
1095 if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
1096 vm.flags |= DISPLAY_FLAGS_VSYNC_LOW;
1098 xilinx_vtc_config_sig(sdi->vtc, &vm);
1101 static void xilinx_sdi_prepare(struct drm_encoder *encoder)
1103 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1106 dev_dbg(sdi->dev, "%s\n", __func__);
1108 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
1109 reg |= XSDI_TX_CTRL_INS_CRC_MASK | XSDI_TX_CTRL_INS_ST352_MASK |
1110 XSDI_TX_CTRL_OVR_ST352_MASK | XSDI_TX_CTRL_INS_SYNC_BIT_MASK |
1111 XSDI_TX_CTRL_INS_EDH_MASK;
1112 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, reg);
1113 xilinx_sdi_writel(sdi->base, XSDI_TX_IER_STAT, XSDI_IER_EN_MASK);
1114 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 1);
1115 xilinx_vtc_reset(sdi->vtc);
1118 static void xilinx_sdi_commit(struct drm_encoder *encoder)
1120 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1123 dev_dbg(sdi->dev, "%s\n", __func__);
1124 xilinx_sdi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
1126 ret = wait_event_interruptible_timeout(sdi->wait_event,
1127 sdi->event_received,
1128 usecs_to_jiffies(GT_TIMEOUT));
1130 dev_err(sdi->dev, "Timeout: GT interrupt not received\n");
1133 sdi->event_received = false;
1134 /* enable sdi bridge, vtc and Axi4s_vid_out_ctrl */
1135 xilinx_en_bridge(sdi);
1136 xilinx_vtc_enable(sdi->vtc);
1137 xilinx_en_axi4s(sdi);
1140 static const struct drm_encoder_helper_funcs xilinx_sdi_encoder_helper_funcs = {
1141 .dpms = xilinx_sdi_encoder_dpms,
1142 .mode_fixup = xilinx_sdi_mode_fixup,
1143 .mode_set = xilinx_sdi_mode_set,
1144 .prepare = xilinx_sdi_prepare,
1145 .commit = xilinx_sdi_commit,
1148 static const struct drm_encoder_funcs xilinx_sdi_encoder_funcs = {
1149 .destroy = drm_encoder_cleanup,
1152 static int xilinx_sdi_bind(struct device *dev, struct device *master,
1155 struct xilinx_sdi *sdi = dev_get_drvdata(dev);
1156 struct drm_encoder *encoder = &sdi->encoder;
1157 struct drm_device *drm_dev = data;
1161 * TODO: The possible CRTCs are 1 now as per current implementation of
1162 * SDI tx drivers. DRM framework can support more than one CRTCs and
1163 * SDI driver can be enhanced for that.
1165 encoder->possible_crtcs = 1;
1167 drm_encoder_init(drm_dev, encoder, &xilinx_sdi_encoder_funcs,
1168 DRM_MODE_ENCODER_TMDS, NULL);
1170 drm_encoder_helper_add(encoder, &xilinx_sdi_encoder_helper_funcs);
1172 ret = xilinx_sdi_create_connector(encoder);
1174 dev_err(sdi->dev, "fail creating connector, ret = %d\n", ret);
1175 drm_encoder_cleanup(encoder);
1180 static void xilinx_sdi_unbind(struct device *dev, struct device *master,
1183 struct xilinx_sdi *sdi = dev_get_drvdata(dev);
1185 xilinx_sdi_encoder_dpms(&sdi->encoder, DRM_MODE_DPMS_OFF);
1186 drm_encoder_cleanup(&sdi->encoder);
1187 drm_connector_cleanup(&sdi->connector);
1190 static const struct component_ops xilinx_sdi_component_ops = {
1191 .bind = xilinx_sdi_bind,
1192 .unbind = xilinx_sdi_unbind,
1195 static int xilinx_sdi_probe(struct platform_device *pdev)
1197 struct device *dev = &pdev->dev;
1198 struct resource *res;
1199 struct xilinx_sdi *sdi;
1200 struct device_node *vtc_node;
1203 sdi = devm_kzalloc(dev, sizeof(*sdi), GFP_KERNEL);
1208 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1209 sdi->base = devm_ioremap_resource(dev, res);
1211 if (IS_ERR(sdi->base)) {
1212 dev_err(dev, "failed to remap io region\n");
1213 return PTR_ERR(sdi->base);
1215 platform_set_drvdata(pdev, sdi);
1217 vtc_node = of_parse_phandle(sdi->dev->of_node, "xlnx,vtc", 0);
1219 dev_err(dev, "vtc node not present\n");
1220 return PTR_ERR(vtc_node);
1222 sdi->vtc = xilinx_vtc_probe(sdi->dev, vtc_node);
1223 of_node_put(vtc_node);
1224 if (IS_ERR(sdi->vtc)) {
1225 dev_err(dev, "failed to probe VTC\n");
1226 return PTR_ERR(sdi->vtc);
1229 /* disable interrupt */
1230 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 0);
1231 irq = platform_get_irq(pdev, 0);
1235 ret = devm_request_threaded_irq(sdi->dev, irq, NULL,
1236 xilinx_sdi_irq_handler, IRQF_ONESHOT,
1237 dev_name(sdi->dev), sdi);
1241 init_waitqueue_head(&sdi->wait_event);
1242 sdi->event_received = false;
1244 return component_add(dev, &xilinx_sdi_component_ops);
1247 static int xilinx_sdi_remove(struct platform_device *pdev)
1249 component_del(&pdev->dev, &xilinx_sdi_component_ops);
1254 static const struct of_device_id xilinx_sdi_of_match[] = {
1255 { .compatible = "xlnx,v-smpte-uhdsdi-tx-ss"},
1258 MODULE_DEVICE_TABLE(of, xilinx_sdi_of_match);
1260 static struct platform_driver sdi_tx_driver = {
1261 .probe = xilinx_sdi_probe,
1262 .remove = xilinx_sdi_remove,
1264 .name = "xlnx,uhdsdi-tx",
1265 .of_match_table = xilinx_sdi_of_match,
1269 module_platform_driver(sdi_tx_driver);
1271 MODULE_AUTHOR("Saurabh Sengar <saurabhs@xilinx.com>");
1272 MODULE_DESCRIPTION("Xilinx FPGA SDI Tx Driver");
1273 MODULE_LICENSE("GPL v2");