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 ST352_BYTE3 0x00
112 #define ST352_BYTE4 0x01
113 #define INVALID_VALUE -1
114 #define GT_TIMEOUT 500
116 * enum payload_line_1 - Payload Ids Line 1 number
117 * @PAYLD_LN1_HD_3_6_12G: line 1 HD,3G,6G or 12G mode value
118 * @PAYLD_LN1_SDPAL: line 1 SD PAL mode value
119 * @PAYLD_LN1_SDNTSC: line 1 SD NTSC mode value
121 enum payload_line_1 {
122 PAYLD_LN1_HD_3_6_12G = 10,
124 PAYLD_LN1_SDNTSC = 13
128 * enum payload_line_2 - Payload Ids Line 2 number
129 * @PAYLD_LN2_HD_3_6_12G: line 2 HD,3G,6G or 12G mode value
130 * @PAYLD_LN2_SDPAL: line 2 SD PAL mode value
131 * @PAYLD_LN2_SDNTSC: line 2 SD NTSC mode value
133 enum payload_line_2 {
134 PAYLD_LN2_HD_3_6_12G = 572,
135 PAYLD_LN2_SDPAL = 322,
136 PAYLD_LN2_SDNTSC = 276
140 * enum sdi_modes - SDI modes
141 * @XSDI_MODE_HD: HD mode
142 * @XSDI_MODE_SD: SD mode
143 * @XSDI_MODE_3GA: 3GA mode
144 * @XSDI_MODE_3GB: 3GB mode
145 * @XSDI_MODE_6G: 6G mode
146 * @XSDI_MODE_12G: 12G mode
158 * struct xilinx_sdi - Core configuration SDI Tx subsystem device structure
159 * @encoder: DRM encoder structure
160 * @connector: DRM connector structure
161 * @vtc: Pointer to VTC structure
162 * @dev: device structure
163 * @base: Base address of SDI subsystem
164 * @mode_flags: SDI operation mode related flags
165 * @wait_event: wait event
166 * @event_received: wait event status
167 * @sdi_mode: configurable SDI mode parameter, supported values are:
174 * @sdi_mod_prop_val: configurable SDI mode parameter value
175 * @sdi_data_strm: configurable SDI data stream parameter
176 * @sdi_data_strm_prop_val: configurable number of SDI data streams
177 * value currently supported are 2, 4 and 8
178 * @is_frac_prop: configurable SDI fractional fps parameter
179 * @is_frac_prop_val: configurable SDI fractional fps parameter value
182 struct drm_encoder encoder;
183 struct drm_connector connector;
184 struct xilinx_vtc *vtc;
188 wait_queue_head_t wait_event;
190 struct drm_property *sdi_mode;
191 u32 sdi_mod_prop_val;
192 struct drm_property *sdi_data_strm;
193 u32 sdi_data_strm_prop_val;
194 struct drm_property *is_frac_prop;
195 bool is_frac_prop_val;
199 * struct xilinx_sdi_display_config - SDI supported modes structure
200 * @mode: drm display mode
201 * @st352_byt2: st352 byte 2 value
202 * index 0 : value for integral fps
203 * index 1 : value for fractional fps
204 * @st352_byt1: st352 byte 1 value
205 * index 0 : value for HD mode
206 * index 1 : value for SD mode
207 * index 2 : value for 3GA
208 * index 3 : value for 3GB
209 * index 4 : value for 6G
210 * index 5 : value for 12G
212 struct xlnx_sdi_display_config {
213 struct drm_display_mode mode;
219 * xlnx_sdi_modes - SDI DRM modes
221 static const struct xlnx_sdi_display_config xlnx_sdi_modes[] = {
222 /* 0 - dummy, VICs start at 1 */
224 /* SD: 720x480i@60Hz */
225 {{ DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
226 801, 858, 0, 240, 244, 247, 262, 0,
227 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
228 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
229 .vrefresh = 60, }, {0x7, 0x6},
230 {0x81, 0x81, 0x81, 0x81, 0x81, 0x81} },
231 /* SD: 720x576i@50Hz */
232 {{ DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
233 795, 864, 0, 288, 290, 293, 312, 0,
234 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
235 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
236 .vrefresh = 50, }, {0x9, 0x9},
237 {0x81, 0x81, 0x81, 0x81, 0x81, 0x81} },
238 /* HD: 1280x720@25Hz */
239 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
240 2990, 3960, 0, 720, 725, 730, 750, 0,
241 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
242 .vrefresh = 25, }, {0x5, 0x5},
243 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
244 /* HD: 1280x720@24Hz */
245 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
246 3155, 4125, 0, 720, 725, 730, 750, 0,
247 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
248 .vrefresh = 24, }, {0x3, 0x2},
249 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
250 /* HD: 1280x720@30Hz */
251 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 2250,
252 2330, 3300, 0, 720, 725, 730, 750, 0,
253 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
254 .vrefresh = 30, }, {0x7, 0x6},
255 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
256 /* HD: 1280x720@50Hz */
257 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
258 1760, 1980, 0, 720, 725, 730, 750, 0,
259 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
260 .vrefresh = 50, }, {0x9, 0x9},
261 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
262 /* HD: 1280x720@60Hz */
263 {{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
264 1430, 1650, 0, 720, 725, 730, 750, 0,
265 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
266 .vrefresh = 60, }, {0xB, 0xA},
267 {0x84, 0x84, 0x88, 0x84, 0x84, 0x84} },
268 /* HD: 1920x1080@24Hz */
269 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
270 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
271 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
272 .vrefresh = 24, }, {0x3, 0x2},
273 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
274 /* HD: 1920x1080@25Hz */
275 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
276 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
277 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
278 .vrefresh = 25, }, {0x5, 0x5},
279 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
280 /* HD: 1920x1080@30Hz */
281 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
282 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
283 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
284 .vrefresh = 30, }, {0x7, 0x6},
285 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
286 /* HD: 1920x1080i@50Hz */
287 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
288 2492, 2640, 0, 540, 542, 547, 562, 0,
289 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
290 DRM_MODE_FLAG_INTERLACE),
291 .vrefresh = 50, }, {0x9, 0x9},
292 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
293 /* HD: 1920x1080i@60Hz */
294 {{ DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
295 2052, 2200, 0, 540, 542, 547, 562, 0,
296 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
297 DRM_MODE_FLAG_INTERLACE),
298 .vrefresh = 60, }, {0x7, 0x6},
299 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
300 /* HD: 2048x1080@30Hz */
301 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2114,
302 2134, 2200, 0, 1080, 1084, 1089, 1125, 0,
303 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
304 .vrefresh = 30, }, {0x7, 0x6},
305 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
306 /* HD: 2048x1080@25Hz */
307 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2448,
308 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
309 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
310 .vrefresh = 25, }, {0x5, 0x5},
311 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
312 /* HD: 2048x1080@24Hz */
313 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 74250, 2048, 2558,
314 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
315 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
316 .vrefresh = 24, }, {0x3, 0x2},
317 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
318 /* 3G: 1920x1080@50Hz */
319 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
320 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
321 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
322 .vrefresh = 50, }, {0x9, 0x9},
323 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
324 /* 3G: 1920x1080@60Hz */
325 {{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
326 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
327 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
328 .vrefresh = 60, }, {0xB, 0xA},
329 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
330 /* 3G: 2048x1080@60Hz */
331 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2136,
332 2180, 2200, 0, 1080, 1084, 1089, 1125, 0,
333 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
334 .vrefresh = 60, }, {0xB, 0xA},
335 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
336 /* 3G: 2048x1080@50Hz */
337 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2448,
338 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
339 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
340 .vrefresh = 50, }, {0x9, 0x9},
341 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
342 /* 3G: 2048x1080@48Hz */
343 {{ DRM_MODE("2048x1080", DRM_MODE_TYPE_DRIVER, 148500, 2048, 2558,
344 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
345 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
346 .vrefresh = 48, }, {0x8, 0x4},
347 {0x85, 0x85, 0x89, 0x8A, 0xC1, 0xC1} },
348 /* 6G: 3840x2160@30Hz */
349 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
350 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
351 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
352 .vrefresh = 30, }, {0x7, 0x6},
353 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
354 /* 6G: 3840x2160@25Hz */
355 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896,
356 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
357 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
358 .vrefresh = 25, }, {0x5, 0x5},
359 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
360 /* 6G: 3840x2160@24Hz */
361 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
362 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
363 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
364 .vrefresh = 24, }, {0x3, 0x2},
365 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
366 /* 6G: 4096x2160@24Hz */
367 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 296704, 4096, 5116,
368 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
369 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
370 .vrefresh = 24, }, {0x3, 0x2},
371 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
372 /* 6G: 4096x2160@25Hz */
373 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064,
374 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
375 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
376 .vrefresh = 25, }, {0x5, 0x5},
377 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
378 /* 6G: 4096x2160@30Hz */
379 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 296704, 4096, 4184,
380 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
381 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
382 .vrefresh = 30, }, {0x7, 0x6},
383 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
384 /* 12G: 3840x2160@50Hz */
385 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
386 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
387 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
388 .vrefresh = 50, }, {0x9, 0x9},
389 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
390 /* 12G: 3840x2160@60Hz */
391 {{ DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
392 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
393 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
394 .vrefresh = 60, }, {0xB, 0xA},
395 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
396 /* 12G: 4096x2160@48Hz */
397 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5116,
398 5204, 5500, 0, 1080, 1084, 1089, 1125, 0,
399 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
400 .vrefresh = 48, }, {0x8, 0x4},
401 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
402 /* 12G: 4096x2160@50Hz */
403 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064,
404 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
405 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
406 .vrefresh = 50, }, {0x9, 0x9},
407 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
408 /* 12G: 4096x2160@60Hz */
409 {{ DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 593408, 4096, 4184,
410 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
411 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
412 .vrefresh = 60, }, {0xB, 0xA},
413 {0x98, 0x98, 0x97, 0x98, 0xC0, 0xCE} },
416 #define connector_to_sdi(c) container_of(c, struct xilinx_sdi, connector)
417 #define encoder_to_sdi(e) container_of(e, struct xilinx_sdi, encoder)
420 * xilinx_sdi_writel - Memory mapped SDI Tx register write
421 * @base: Pointer to SDI Tx registers base
422 * @offset: Register offset
423 * @val: value to be written
425 * This function writes the value to SDI TX registers
427 static inline void xilinx_sdi_writel(void __iomem *base, int offset, u32 val)
429 writel(val, base + offset);
433 * xilinx_sdi_readl - Memory mapped SDI Tx register read
434 * @base: Pointer to SDI Tx registers base
435 * @offset: Register offset
437 * Return: The contents of the SDI Tx register
439 * This function returns the contents of the corresponding SDI Tx register.
441 static inline u32 xilinx_sdi_readl(void __iomem *base, int offset)
443 return readl(base + offset);
447 * xilinx_en_axi4s - Enable SDI Tx AXI4S-to-Video core
448 * @sdi: Pointer to SDI Tx structure
450 * This function enables the SDI Tx AXI4S-to-Video core.
452 static void xilinx_en_axi4s(struct xilinx_sdi *sdi)
456 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
457 data |= XSDI_TX_AXI4S_CTRL_EN_MASK;
458 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
462 * xilinx_en_bridge - Enable SDI Tx bridge
463 * @sdi: Pointer to SDI Tx structure
465 * This function enables the SDI Tx bridge.
467 static void xilinx_en_bridge(struct xilinx_sdi *sdi)
471 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
472 data |= XSDI_TX_BRIDGE_CTRL_EN_MASK;
473 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
477 * xilinx_sdi_set_default_drm_properties - Configure SDI DRM
478 * properties with their default values
479 * @sdi: SDI structure having the updated user parameters
482 xilinx_sdi_set_default_drm_properties(struct xilinx_sdi *sdi)
484 drm_object_property_set_value(&sdi->connector.base,
486 drm_object_property_set_value(&sdi->connector.base,
487 sdi->sdi_data_strm, 0);
488 drm_object_property_set_value(&sdi->connector.base,
489 sdi->is_frac_prop, 0);
493 * xilinx_sdi_irq_handler - SDI Tx interrupt
497 * Return: IRQ_HANDLED for all cases.
499 * This is the compact GT ready interrupt.
501 static irqreturn_t xilinx_sdi_irq_handler(int irq, void *data)
503 struct xilinx_sdi *sdi = (struct xilinx_sdi *)data;
506 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_ISR_STAT);
508 if (reg & XSDI_GTTX_RSTDONE_INTR_MASK)
509 dev_dbg(sdi->dev, "GT reset interrupt received\n");
510 if (reg & XSDI_TX_CE_ALIGN_ERR_INTR_MASK)
511 dev_err_ratelimited(sdi->dev, "SDI SD CE align error\n");
512 if (reg & XSDI_OVERFLOW_INTR_MASK)
513 dev_err_ratelimited(sdi->dev, "AXI-4 Stream Overflow error\n");
514 if (reg & XSDI_UNDERFLOW_INTR_MASK)
515 dev_err_ratelimited(sdi->dev, "AXI-4 Stream Underflow error\n");
516 xilinx_sdi_writel(sdi->base, XSDI_TX_ISR_STAT,
517 reg & ~(XSDI_AXI4S_VID_LOCK_INTR_MASK));
519 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_STS_SB_TDATA);
520 if (reg & XSDI_TX_TDATA_GT_RESETDONE_MASK) {
521 sdi->event_received = true;
522 wake_up_interruptible(&sdi->wait_event);
528 * xilinx_sdi_set_payload_line - set ST352 packet line number
529 * @sdi: Pointer to SDI Tx structure
530 * @line_1: line number used to insert st352 packet for field 1.
531 * @line_2: line number used to insert st352 packet for field 2.
533 * This function set 352 packet line number.
535 static void xilinx_sdi_set_payload_line(struct xilinx_sdi *sdi,
536 u32 line_1, u32 line_2)
540 data = ((line_1 & XSDI_TX_ST352_LINE_MASK) |
541 ((line_2 & XSDI_TX_ST352_LINE_MASK) <<
542 XSDI_TX_ST352_LINE_F2_SHIFT));
544 xilinx_sdi_writel(sdi->base, XSDI_TX_ST352_LINE, data);
546 data = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
547 data |= (1 << XSDI_TX_CTRL_ST352_F2_EN_SHIFT);
549 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, data);
553 * xilinx_sdi_set_payload_data - set ST352 packet payload
554 * @sdi: Pointer to SDI Tx structure
555 * @data_strm: data stream number
556 * @payload: st352 packet payload
558 * This function set ST352 payload data to corresponding stream.
560 static void xilinx_sdi_set_payload_data(struct xilinx_sdi *sdi,
561 u32 data_strm, u32 payload)
563 xilinx_sdi_writel(sdi->base,
564 (XSDI_TX_ST352_DATA_CH0 + (data_strm * 4)), payload);
568 * xilinx_sdi_set_display_disable - Disable the SDI Tx IP core enable
570 * @sdi: SDI structure having the updated user parameters
572 * This function takes the SDI strucure and disables the core enable bit
573 * of core configuration register.
575 static void xilinx_sdi_set_display_disable(struct xilinx_sdi *sdi)
579 for (i = 0; i < SDI_MAX_DATASTREAM; i++)
580 xilinx_sdi_set_payload_data(sdi, i, 0);
582 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 0);
583 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, 0);
587 * xilinx_sdi_payload_config - config the SDI payload parameters
588 * @sdi: pointer Xilinx SDI Tx structure
589 * @mode: display mode
591 * This function config the SDI st352 payload parameter.
593 static void xilinx_sdi_payload_config(struct xilinx_sdi *sdi, u32 mode)
595 u32 payload_1, payload_2;
599 payload_1 = PAYLD_LN1_SDPAL;
600 payload_2 = PAYLD_LN2_SDPAL;
607 payload_1 = PAYLD_LN1_HD_3_6_12G;
608 payload_2 = PAYLD_LN2_HD_3_6_12G;
616 xilinx_sdi_set_payload_line(sdi, payload_1, payload_2);
620 * xilinx_set_sdi_mode - Set mode parameters in SDI Tx
621 * @sdi: pointer Xilinx SDI Tx structure
622 * @mode: SDI Tx display mode
623 * @is_frac: 0 - integer 1 - fractional
624 * @mux_ptrn: specifiy the data stream interleaving pattern to be used
625 * This function config the SDI st352 payload parameter.
627 static void xilinx_set_sdi_mode(struct xilinx_sdi *sdi, u32 mode,
628 bool is_frac, u32 mux_ptrn)
632 xilinx_sdi_payload_config(sdi, mode);
634 data = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
635 data &= ~((XSDI_TX_CTRL_MODE_MASK << XSDI_TX_CTRL_MODE_SHIFT) |
636 (XSDI_TX_CTRL_M_MASK) | (XSDI_TX_CTRL_MUX_MASK
637 << XSDI_TX_CTRL_MUX_SHIFT));
639 data |= (((mode & XSDI_TX_CTRL_MODE_MASK)
640 << XSDI_TX_CTRL_MODE_SHIFT) |
641 (is_frac << XSDI_TX_CTRL_M_SHIFT) |
642 ((mux_ptrn & XSDI_TX_CTRL_MUX_MASK) << XSDI_TX_CTRL_MUX_SHIFT));
644 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, data);
648 * xilinx_sdi_set_config_parameters - Configure SDI Tx registers with parameters
649 * given from user application.
650 * @sdi: SDI structure having the updated user parameters
652 * This function takes the SDI structure having drm_property parameters
653 * configured from user application and writes them into SDI IP registers.
655 static void xilinx_sdi_set_config_parameters(struct xilinx_sdi *sdi)
658 int mux_ptrn = INVALID_VALUE;
661 mode = sdi->sdi_mod_prop_val;
662 is_frac = sdi->is_frac_prop_val;
666 mux_ptrn = XSDI_TX_MUX_SD_HD_3GA;
669 mux_ptrn = XSDI_TX_MUX_3GB;
672 if (sdi->sdi_data_strm_prop_val == 4)
673 mux_ptrn = XSDI_TX_MUX_4STREAM_6G;
674 else if (sdi->sdi_data_strm_prop_val == 8)
675 mux_ptrn = XSDI_TX_MUX_8STREAM_6G_12G;
678 if (sdi->sdi_data_strm_prop_val == 8)
679 mux_ptrn = XSDI_TX_MUX_8STREAM_6G_12G;
685 if (mux_ptrn == INVALID_VALUE) {
686 dev_err(sdi->dev, "%d data stream not supported for %d mode",
687 sdi->sdi_data_strm_prop_val, mode);
690 xilinx_set_sdi_mode(sdi, mode, is_frac, mux_ptrn);
694 * xilinx_sdi_connector_set_property - implementation of drm_connector_funcs
695 * set_property invoked by IOCTL call to DRM_IOCTL_MODE_OBJ_SETPROPERTY
697 * @base_connector: pointer Xilinx SDI connector
698 * @property: pointer to the drm_property structure
699 * @value: SDI parameter value that is configured from user application
701 * This function takes a drm_property name and value given from user application
702 * and update the SDI structure property varabiles with the values.
703 * These values are later used to configure the SDI Rx IP.
705 * Return: 0 on success OR -EINVAL if setting property fails
708 xilinx_sdi_connector_set_property(struct drm_connector *base_connector,
709 struct drm_property *property,
712 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
714 if (property == sdi->sdi_mode)
715 sdi->sdi_mod_prop_val = (unsigned int)value;
716 else if (property == sdi->sdi_data_strm)
717 sdi->sdi_data_strm_prop_val = (unsigned int)value;
718 else if (property == sdi->is_frac_prop)
719 sdi->is_frac_prop_val = !!value;
726 * xilinx_sdi_get_mode_id - Search for a video mode in the supported modes table
728 * @mode: mode being searched
730 * Return: true if mode is found
732 static int xilinx_sdi_get_mode_id(struct drm_display_mode *mode)
736 for (i = 0; i < ARRAY_SIZE(xlnx_sdi_modes); i++)
737 if (drm_mode_equal(&xlnx_sdi_modes[i].mode, mode))
743 * xilinx_sdi_drm_add_modes - Adds SDI supported modes
744 * @connector: pointer Xilinx SDI connector
746 * Return: Count of modes added
748 * This function adds the SDI modes supported and returns its count
750 static int xilinx_sdi_drm_add_modes(struct drm_connector *connector)
752 int i, num_modes = 0;
753 struct drm_display_mode *mode;
754 struct drm_device *dev = connector->dev;
756 for (i = 0; i < ARRAY_SIZE(xlnx_sdi_modes); i++) {
757 const struct drm_display_mode *ptr = &xlnx_sdi_modes[i].mode;
759 mode = drm_mode_duplicate(dev, ptr);
761 drm_mode_probed_add(connector, mode);
768 static int xilinx_sdi_connector_dpms(struct drm_connector *connector,
771 return drm_helper_connector_dpms(connector, mode);
774 static enum drm_connector_status
775 xilinx_sdi_detect(struct drm_connector *connector, bool force)
777 return connector_status_connected;
780 static void xilinx_sdi_connector_destroy(struct drm_connector *connector)
782 drm_connector_unregister(connector);
783 drm_connector_cleanup(connector);
784 connector->dev = NULL;
787 static const struct drm_connector_funcs xilinx_sdi_connector_funcs = {
788 .dpms = xilinx_sdi_connector_dpms,
789 .detect = xilinx_sdi_detect,
790 .fill_modes = drm_helper_probe_single_connector_modes,
791 .destroy = xilinx_sdi_connector_destroy,
792 .set_property = xilinx_sdi_connector_set_property,
795 static struct drm_encoder *
796 xilinx_sdi_best_encoder(struct drm_connector *connector)
798 return &(connector_to_sdi(connector)->encoder);
801 static int xilinx_sdi_get_modes(struct drm_connector *connector)
803 return xilinx_sdi_drm_add_modes(connector);
806 static struct drm_connector_helper_funcs xilinx_sdi_connector_helper_funcs = {
807 .get_modes = xilinx_sdi_get_modes,
808 .best_encoder = xilinx_sdi_best_encoder,
812 * xilinx_sdi_drm_connector_create_property - create SDI connector properties
814 * @base_connector: pointer to Xilinx SDI connector
816 * This function takes the xilinx SDI connector component and defines
817 * the drm_property variables with their default values.
820 xilinx_sdi_drm_connector_create_property(struct drm_connector *base_connector)
822 struct drm_device *dev = base_connector->dev;
823 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
825 sdi->is_frac_prop = drm_property_create_bool(dev, 1, "is_frac");
826 sdi->sdi_mode = drm_property_create_range(dev, 0,
828 sdi->sdi_data_strm = drm_property_create_range(dev, 0,
829 "sdi_data_stream", 2, 8);
833 * xilinx_sdi_drm_connector_attach_property - attach SDI connector
836 * @base_connector: pointer to Xilinx SDI connector
839 xilinx_sdi_drm_connector_attach_property(struct drm_connector *base_connector)
841 struct xilinx_sdi *sdi = connector_to_sdi(base_connector);
842 struct drm_mode_object *obj = &base_connector->base;
845 drm_object_attach_property(obj, sdi->sdi_mode, 0);
847 if (sdi->sdi_data_strm)
848 drm_object_attach_property(obj, sdi->sdi_data_strm, 0);
850 if (sdi->is_frac_prop)
851 drm_object_attach_property(obj, sdi->is_frac_prop, 0);
854 static int xilinx_sdi_create_connector(struct drm_encoder *encoder)
856 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
857 struct drm_connector *connector = &sdi->connector;
860 connector->polled = DRM_CONNECTOR_POLL_HPD;
861 connector->interlace_allowed = true;
863 ret = drm_connector_init(encoder->dev, connector,
864 &xilinx_sdi_connector_funcs,
865 DRM_MODE_CONNECTOR_Unknown);
867 dev_err(sdi->dev, "Failed to initialize connector with drm\n");
871 drm_connector_helper_add(connector, &xilinx_sdi_connector_helper_funcs);
872 drm_connector_register(connector);
873 drm_mode_connector_attach_encoder(connector, encoder);
874 xilinx_sdi_drm_connector_create_property(connector);
875 xilinx_sdi_drm_connector_attach_property(connector);
880 static bool xilinx_sdi_mode_fixup(struct drm_encoder *encoder,
881 const struct drm_display_mode *mode,
882 struct drm_display_mode *adjusted_mode)
888 * xilinx_sdi_set_display_enable - Enables the SDI Tx IP core enable
890 * @sdi: SDI structure having the updated user parameters
892 * This function takes the SDI strucure and enables the core enable bit
893 * of core configuration register.
895 static void xilinx_sdi_set_display_enable(struct xilinx_sdi *sdi)
899 data = xilinx_sdi_readl(sdi->base, XSDI_TX_RST_CTRL);
900 data |= XSDI_TX_CTRL_EN_MASK;
901 /* start sdi stream */
902 xilinx_sdi_writel(sdi->base, XSDI_TX_RST_CTRL, data);
905 static void xilinx_sdi_encoder_dpms(struct drm_encoder *encoder,
908 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
910 dev_dbg(sdi->dev, "encoder dpms state: %d\n", mode);
913 case DRM_MODE_DPMS_ON:
914 xilinx_sdi_set_display_enable(sdi);
917 xilinx_sdi_set_display_disable(sdi);
918 xilinx_sdi_set_default_drm_properties(sdi);
923 * xilinx_sdi_calc_st352_payld - calculate the st352 payload
925 * @sdi: pointer to SDI Tx structure
926 * @mode: DRM display mode
928 * This function calculates the st352 payload to be configured.
929 * Please refer to SMPTE ST352 documents for it.
930 * Return: return st352 payload
932 static u32 xilinx_sdi_calc_st352_payld(struct xilinx_sdi *sdi,
933 struct drm_display_mode *mode)
937 u32 id, sdi_mode = sdi->sdi_mod_prop_val;
938 bool is_frac = sdi->is_frac_prop_val;
939 u32 byt3 = ST352_BYTE3;
941 id = xilinx_sdi_get_mode_id(mode);
942 dev_dbg(sdi->dev, "mode id: %d\n", id);
943 if (mode->hdisplay == 2048 || mode->hdisplay == 4096)
944 byt3 |= XST352_2048_SHIFT;
945 /* byte 2 calculation */
946 is_p = !(mode->flags & DRM_MODE_FLAG_INTERLACE);
947 smpl_r = xlnx_sdi_modes[id].st352_byt2[is_frac];
948 byt2 = (is_p << XST352_PROG_SHIFT) | smpl_r;
949 if (mode->vtotal >= 1125)
950 byt2 |= (is_p << XST352_TRANS_SHIFT);
951 /* byte 1 calculation */
952 byt1 = xlnx_sdi_modes[id].st352_byt1[sdi_mode];
954 return (ST352_BYTE4 << 24 | byt3 << 16 | byt2 << 8 | byt1);
958 * xilinx_sdi_mode_set - drive the SDI timing parameters
960 * @encoder: pointer to Xilinx DRM encoder
961 * @mode: DRM kernel-internal display mode structure
962 * @adjusted_mode: SDI panel timing parameters
964 * This function derives the SDI IP timing parameters from the timing
965 * values given by VTC driver.
967 static void xilinx_sdi_mode_set(struct drm_encoder *encoder,
968 struct drm_display_mode *mode,
969 struct drm_display_mode *adjusted_mode)
971 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
975 xilinx_sdi_set_config_parameters(sdi);
977 /* set st352 payloads */
978 payload = xilinx_sdi_calc_st352_payld(sdi, adjusted_mode);
979 dev_dbg(sdi->dev, "payload : %0x\n", payload);
981 for (i = 0; i < sdi->sdi_data_strm_prop_val / 2; i++) {
982 if (sdi->sdi_mod_prop_val == XSDI_MODE_3GB)
983 payload |= (i << 1) << XSDI_CH_SHIFT;
984 xilinx_sdi_set_payload_data(sdi, i, payload);
987 /* UHDSDI is fixed 2 pixels per clock, horizontal timings div by 2 */
988 vm.hactive = adjusted_mode->hdisplay / PIXELS_PER_CLK;
989 vm.hfront_porch = (adjusted_mode->hsync_start -
990 adjusted_mode->hdisplay) / PIXELS_PER_CLK;
991 vm.hback_porch = (adjusted_mode->htotal -
992 adjusted_mode->hsync_end) / PIXELS_PER_CLK;
993 vm.hsync_len = (adjusted_mode->hsync_end -
994 adjusted_mode->hsync_start) / PIXELS_PER_CLK;
996 vm.vactive = adjusted_mode->vdisplay;
997 vm.vfront_porch = adjusted_mode->vsync_start -
998 adjusted_mode->vdisplay;
999 vm.vback_porch = adjusted_mode->vtotal -
1000 adjusted_mode->vsync_end;
1001 vm.vsync_len = adjusted_mode->vsync_end -
1002 adjusted_mode->vsync_start;
1004 xilinx_vtc_config_sig(sdi->vtc, &vm);
1007 static void xilinx_sdi_prepare(struct drm_encoder *encoder)
1009 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1012 dev_dbg(sdi->dev, "%s\n", __func__);
1014 reg = xilinx_sdi_readl(sdi->base, XSDI_TX_MDL_CTRL);
1015 reg |= XSDI_TX_CTRL_INS_CRC_MASK | XSDI_TX_CTRL_INS_ST352_MASK |
1016 XSDI_TX_CTRL_OVR_ST352_MASK | XSDI_TX_CTRL_INS_SYNC_BIT_MASK |
1017 XSDI_TX_CTRL_INS_EDH_MASK;
1018 xilinx_sdi_writel(sdi->base, XSDI_TX_MDL_CTRL, reg);
1019 xilinx_sdi_writel(sdi->base, XSDI_TX_IER_STAT, XSDI_IER_EN_MASK);
1020 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 1);
1021 xilinx_vtc_reset(sdi->vtc);
1024 static void xilinx_sdi_commit(struct drm_encoder *encoder)
1026 struct xilinx_sdi *sdi = encoder_to_sdi(encoder);
1029 dev_dbg(sdi->dev, "%s\n", __func__);
1030 xilinx_sdi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
1032 ret = wait_event_interruptible_timeout(sdi->wait_event,
1033 sdi->event_received,
1034 usecs_to_jiffies(GT_TIMEOUT));
1036 dev_err(sdi->dev, "Timeout: GT interrupt not received\n");
1039 sdi->event_received = false;
1040 /* enable sdi bridge, vtc and Axi4s_vid_out_ctrl */
1041 xilinx_en_bridge(sdi);
1042 xilinx_vtc_enable(sdi->vtc);
1043 xilinx_en_axi4s(sdi);
1046 static const struct drm_encoder_helper_funcs xilinx_sdi_encoder_helper_funcs = {
1047 .dpms = xilinx_sdi_encoder_dpms,
1048 .mode_fixup = xilinx_sdi_mode_fixup,
1049 .mode_set = xilinx_sdi_mode_set,
1050 .prepare = xilinx_sdi_prepare,
1051 .commit = xilinx_sdi_commit,
1054 static const struct drm_encoder_funcs xilinx_sdi_encoder_funcs = {
1055 .destroy = drm_encoder_cleanup,
1058 static int xilinx_sdi_bind(struct device *dev, struct device *master,
1061 struct xilinx_sdi *sdi = dev_get_drvdata(dev);
1062 struct drm_encoder *encoder = &sdi->encoder;
1063 struct drm_device *drm_dev = data;
1067 * TODO: The possible CRTCs are 1 now as per current implementation of
1068 * SDI tx drivers. DRM framework can support more than one CRTCs and
1069 * SDI driver can be enhanced for that.
1071 encoder->possible_crtcs = 1;
1073 drm_encoder_init(drm_dev, encoder, &xilinx_sdi_encoder_funcs,
1074 DRM_MODE_ENCODER_TMDS, NULL);
1076 drm_encoder_helper_add(encoder, &xilinx_sdi_encoder_helper_funcs);
1078 ret = xilinx_sdi_create_connector(encoder);
1080 dev_err(sdi->dev, "fail creating connector, ret = %d\n", ret);
1081 drm_encoder_cleanup(encoder);
1086 static void xilinx_sdi_unbind(struct device *dev, struct device *master,
1089 struct xilinx_sdi *sdi = dev_get_drvdata(dev);
1091 xilinx_sdi_encoder_dpms(&sdi->encoder, DRM_MODE_DPMS_OFF);
1092 drm_encoder_cleanup(&sdi->encoder);
1093 drm_connector_cleanup(&sdi->connector);
1096 static const struct component_ops xilinx_sdi_component_ops = {
1097 .bind = xilinx_sdi_bind,
1098 .unbind = xilinx_sdi_unbind,
1101 static int xilinx_sdi_probe(struct platform_device *pdev)
1103 struct device *dev = &pdev->dev;
1104 struct resource *res;
1105 struct xilinx_sdi *sdi;
1106 struct device_node *vtc_node;
1109 sdi = devm_kzalloc(dev, sizeof(*sdi), GFP_KERNEL);
1114 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1115 sdi->base = devm_ioremap_resource(dev, res);
1117 if (IS_ERR(sdi->base)) {
1118 dev_err(dev, "failed to remap io region\n");
1119 return PTR_ERR(sdi->base);
1121 platform_set_drvdata(pdev, sdi);
1123 vtc_node = of_parse_phandle(sdi->dev->of_node, "xlnx,vtc", 0);
1125 dev_err(dev, "vtc node not present\n");
1126 return PTR_ERR(vtc_node);
1128 sdi->vtc = xilinx_vtc_probe(sdi->dev, vtc_node);
1129 of_node_put(vtc_node);
1130 if (IS_ERR(sdi->vtc)) {
1131 dev_err(dev, "failed to probe VTC\n");
1132 return PTR_ERR(sdi->vtc);
1135 /* disable interrupt */
1136 xilinx_sdi_writel(sdi->base, XSDI_TX_GLBL_IER, 0);
1137 irq = platform_get_irq(pdev, 0);
1141 ret = devm_request_threaded_irq(sdi->dev, irq, NULL,
1142 xilinx_sdi_irq_handler, IRQF_ONESHOT,
1143 dev_name(sdi->dev), sdi);
1147 init_waitqueue_head(&sdi->wait_event);
1148 sdi->event_received = false;
1150 return component_add(dev, &xilinx_sdi_component_ops);
1153 static int xilinx_sdi_remove(struct platform_device *pdev)
1155 component_del(&pdev->dev, &xilinx_sdi_component_ops);
1160 static const struct of_device_id xilinx_sdi_of_match[] = {
1161 { .compatible = "xlnx,v-smpte-uhdsdi-tx-ss"},
1164 MODULE_DEVICE_TABLE(of, xilinx_sdi_of_match);
1166 static struct platform_driver sdi_tx_driver = {
1167 .probe = xilinx_sdi_probe,
1168 .remove = xilinx_sdi_remove,
1170 .name = "xlnx,uhdsdi-tx",
1171 .of_match_table = xilinx_sdi_of_match,
1175 module_platform_driver(sdi_tx_driver);
1177 MODULE_AUTHOR("Saurabh Sengar <saurabhs@xilinx.com>");
1178 MODULE_DESCRIPTION("Xilinx FPGA SDI Tx Driver");
1179 MODULE_LICENSE("GPL v2");