]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/blob - drivers/gpu/drm/xilinx/xilinx_vtc.c
1db36aeca542222b651b24962588593154862677
[vajnamar/linux-xlnx.git] / drivers / gpu / drm / xilinx / xilinx_vtc.c
1 /*
2  * Video Timing Controller support for Xilinx DRM KMS
3  *
4  *  Copyright (C) 2013 Xilinx, Inc.
5  *
6  *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <drm/drmP.h>
19
20 #include <linux/device.h>
21 #include <linux/err.h>
22 #include <linux/interrupt.h>
23 #include <linux/io.h>
24 #include <linux/of_address.h>
25 #include <linux/of_irq.h>
26 #include <linux/slab.h>
27
28 #include <video/videomode.h>
29
30 #include "xilinx_drm_drv.h"
31 #include "xilinx_vtc.h"
32
33 /* register offsets */
34 #define VTC_CTL         0x000   /* control */
35 #define VTC_STATS       0x004   /* status */
36 #define VTC_ERROR       0x008   /* error */
37
38 #define VTC_GASIZE      0x060   /* generator active size */
39 #define VTC_GPOL        0x06c   /* generator polarity */
40 #define VTC_GHSIZE      0x070   /* generator frame horizontal size */
41 #define VTC_GVSIZE      0x074   /* generator frame vertical size */
42 #define VTC_GHSYNC      0x078   /* generator horizontal sync */
43 #define VTC_GVBHOFF     0x07c   /* generator vblank horizontal offset */
44 #define VTC_GVSYNC      0x080   /* generator vertical sync */
45 #define VTC_GVSHOFF     0x084   /* generator vsync horizontal offset */
46
47 #define VTC_RESET       0x000   /* reset register */
48 #define VTC_ISR         0x004   /* interrupt status register */
49 #define VTC_IER         0x00c   /* interrupt enable register */
50
51 /* control register bit */
52 #define VTC_CTL_FIP     (1 << 6)        /* field id output polarity */
53 #define VTC_CTL_ACP     (1 << 5)        /* active chroma output polarity */
54 #define VTC_CTL_AVP     (1 << 4)        /* active video output polarity */
55 #define VTC_CTL_HSP     (1 << 3)        /* hori sync output polarity */
56 #define VTC_CTL_VSP     (1 << 2)        /* vert sync output polarity */
57 #define VTC_CTL_HBP     (1 << 1)        /* hori blank output polarity */
58 #define VTC_CTL_VBP     (1 << 0)        /* vert blank output polarity */
59
60 #define VTC_CTL_FIPSS   (1 << 26)       /* field id output polarity source */
61 #define VTC_CTL_ACPSS   (1 << 25)       /* active chroma out polarity source */
62 #define VTC_CTL_AVPSS   (1 << 24)       /* active video out polarity source */
63 #define VTC_CTL_HSPSS   (1 << 23)       /* hori sync out polarity source */
64 #define VTC_CTL_VSPSS   (1 << 22)       /* vert sync out polarity source */
65 #define VTC_CTL_HBPSS   (1 << 21)       /* hori blank out polarity source */
66 #define VTC_CTL_VBPSS   (1 << 20)       /* vert blank out polarity source */
67
68 #define VTC_CTL_VCSS    (1 << 18)       /* chroma source select */
69 #define VTC_CTL_VASS    (1 << 17)       /* vertical offset source select */
70 #define VTC_CTL_VBSS    (1 << 16)       /* vertical sync end source select */
71 #define VTC_CTL_VSSS    (1 << 15)       /* vertical sync start source select */
72 #define VTC_CTL_VFSS    (1 << 14)       /* vertical active size source select */
73 #define VTC_CTL_VTSS    (1 << 13)       /* vertical frame size source select */
74
75 #define VTC_CTL_HBSS    (1 << 11)       /* horiz sync end source select */
76 #define VTC_CTL_HSSS    (1 << 10)       /* horiz sync start source select */
77 #define VTC_CTL_HFSS    (1 << 9)        /* horiz active size source select */
78 #define VTC_CTL_HTSS    (1 << 8)        /* horiz frame size source select */
79
80 #define VTC_CTL_GE      (1 << 2)        /* vtc generator enable */
81 #define VTC_CTL_RU      (1 << 1)        /* vtc register update */
82
83 /* vtc generator horizontal 1 */
84 #define VTC_GH1_BPSTART_MASK   0x1fff0000       /* horiz back porch start */
85 #define VTC_GH1_BPSTART_SHIFT  16
86 #define VTC_GH1_SYNCSTART_MASK 0x00001fff
87
88 /* vtc generator vertical 1 (filed 0) */
89 #define VTC_GV1_BPSTART_MASK   0x1fff0000       /* vertical back porch start */
90 #define VTC_GV1_BPSTART_SHIFT  16
91 #define VTC_GV1_SYNCSTART_MASK 0x00001fff
92
93 /* vtc generator/detector vblank/vsync horizontal offset registers */
94 #define VTC_XVXHOX_HEND_MASK    0x1fff0000      /* horiz offset end */
95 #define VTC_XVXHOX_HEND_SHIFT   16              /* horiz offset end shift */
96 #define VTC_XVXHOX_HSTART_MASK  0x00001fff      /* horiz offset start */
97
98 /* reset register bit definition */
99 #define VTC_RESET_RESET         (1 << 31)       /* Software Reset */
100
101 /* interrupt status/enable register bit definition */
102 #define VTC_IXR_FSYNC15         (1 << 31)       /* frame sync interrupt 15 */
103 #define VTC_IXR_FSYNC14         (1 << 30)       /* frame sync interrupt 14 */
104 #define VTC_IXR_FSYNC13         (1 << 29)       /* frame sync interrupt 13 */
105 #define VTC_IXR_FSYNC12         (1 << 28)       /* frame sync interrupt 12 */
106 #define VTC_IXR_FSYNC11         (1 << 27)       /* frame sync interrupt 11 */
107 #define VTC_IXR_FSYNC10         (1 << 26)       /* frame sync interrupt 10 */
108 #define VTC_IXR_FSYNC09         (1 << 25)       /* frame sync interrupt 09 */
109 #define VTC_IXR_FSYNC08         (1 << 24)       /* frame sync interrupt 08 */
110 #define VTC_IXR_FSYNC07         (1 << 23)       /* frame sync interrupt 07 */
111 #define VTC_IXR_FSYNC06         (1 << 22)       /* frame sync interrupt 06 */
112 #define VTC_IXR_FSYNC05         (1 << 21)       /* frame sync interrupt 05 */
113 #define VTC_IXR_FSYNC04         (1 << 20)       /* frame sync interrupt 04 */
114 #define VTC_IXR_FSYNC03         (1 << 19)       /* frame sync interrupt 03 */
115 #define VTC_IXR_FSYNC02         (1 << 18)       /* frame sync interrupt 02 */
116 #define VTC_IXR_FSYNC01         (1 << 17)       /* frame sync interrupt 01 */
117 #define VTC_IXR_FSYNC00         (1 << 16)       /* frame sync interrupt 00 */
118 #define VTC_IXR_FSYNCALL_MASK   (VTC_IXR_FSYNC00 |      \
119                                 VTC_IXR_FSYNC01 |       \
120                                 VTC_IXR_FSYNC02 |       \
121                                 VTC_IXR_FSYNC03 |       \
122                                 VTC_IXR_FSYNC04 |       \
123                                 VTC_IXR_FSYNC05 |       \
124                                 VTC_IXR_FSYNC06 |       \
125                                 VTC_IXR_FSYNC07 |       \
126                                 VTC_IXR_FSYNC08 |       \
127                                 VTC_IXR_FSYNC09 |       \
128                                 VTC_IXR_FSYNC10 |       \
129                                 VTC_IXR_FSYNC11 |       \
130                                 VTC_IXR_FSYNC12 |       \
131                                 VTC_IXR_FSYNC13 |       \
132                                 VTC_IXR_FSYNC14 |       \
133                                 VTC_IXR_FSYNC15)
134
135 #define VTC_IXR_G_AV            (1 << 13)       /* generator actv video intr */
136 #define VTC_IXR_G_VBLANK        (1 << 12)       /* generator vblank interrupt */
137 #define VTC_IXR_G_ALL_MASK      (VTC_IXR_G_AV | \
138                                  VTC_IXR_G_VBLANK)      /* all generator intr */
139
140 #define VTC_IXR_D_AV            (1 << 11)       /* detector active video intr */
141 #define VTC_IXR_D_VBLANK        (1 << 10)       /* detector vblank interrupt */
142 #define VTC_IXR_D_ALL_MASK      (VTC_IXR_D_AV | \
143                                 VTC_IXR_D_VBLANK)       /* all detector intr */
144
145 #define VTC_IXR_LOL             (1 << 9)        /* lock loss */
146 #define VTC_IXR_LO              (1 << 8)        /* lock  */
147 #define VTC_IXR_LOCKALL_MASK    (VTC_IXR_LOL |  \
148                                 VTC_IXR_LO)     /* all signal lock intr */
149
150 #define VTC_IXR_ACL     (1 << 21)       /* active chroma signal lock */
151 #define VTC_IXR_AVL     (1 << 20)       /* active video signal lock */
152 #define VTC_IXR_HSL     (1 << 19)       /* horizontal sync signal lock */
153 #define VTC_IXR_VSL     (1 << 18)       /* vertical sync signal lock */
154 #define VTC_IXR_HBL     (1 << 17)       /* horizontal blank signal lock */
155 #define VTC_IXR_VBL     (1 << 16)       /* vertical blank signal lock */
156
157 /* mask for all interrupts */
158 #define VTC_IXR_ALLINTR_MASK    (VTC_IXR_FSYNCALL_MASK |        \
159                                 VTC_IXR_G_ALL_MASK |            \
160                                 VTC_IXR_D_ALL_MASK |            \
161                                 VTC_IXR_LOCKALL_MASK)
162 /**
163  * struct xilinx_vtc - Xilinx VTC object
164  *
165  * @base: base addr
166  * @irq: irq
167  * @vblank_fn: vblank handler func
168  * @vblank_data: vblank handler private data
169  */
170 struct xilinx_vtc {
171         void __iomem *base;
172         int irq;
173         void (*vblank_fn)(void *);
174         void *vblank_data;
175 };
176
177 /**
178  * struct xilinx_vtc_polarity - vtc polarity config
179  *
180  * @active_chroma: active chroma polarity
181  * @active_video: active video polarity
182  * @field_id: field ID polarity
183  * @vblank: vblank polarity
184  * @vsync: vsync polarity
185  * @hblank: hblank polarity
186  * @hsync: hsync polarity
187  */
188 struct xilinx_vtc_polarity {
189         u8 active_chroma;
190         u8 active_video;
191         u8 field_id;
192         u8 vblank;
193         u8 vsync;
194         u8 hblank;
195         u8 hsync;
196 };
197
198 /**
199  * struct xilinx_vtc_hori_offset - vtc horizontal offset config
200  *
201  * @vblank_hori_start: vblank horizontal start
202  * @vblank_hori_end: vblank horizontal end
203  * @vsync_hori_start: vsync horizontal start
204  * @vsync_hori_end: vsync horizontal end
205  */
206 struct xilinx_vtc_hori_offset {
207         u16 vblank_hori_start;
208         u16 vblank_hori_end;
209         u16 vsync_hori_start;
210         u16 vsync_hori_end;
211 };
212
213 /**
214  * struct xilinx_vtc_src_config - vtc source config
215  *
216  * @field_id_pol: filed id polarity source
217  * @active_chroma_pol: active chroma polarity source
218  * @active_video_pol: active video polarity source
219  * @hsync_pol: hsync polarity source
220  * @vsync_pol: vsync polarity source
221  * @hblank_pol: hblnak polarity source
222  * @vblank_pol: vblank polarity source
223  * @vchroma: vchroma polarity start source
224  * @vactive: vactive size source
225  * @vbackporch: vbackporch start source
226  * @vsync: vsync start source
227  * @vfrontporch: vfrontporch start source
228  * @vtotal: vtotal size source
229  * @hactive: hactive start source
230  * @hbackporch: hbackporch start source
231  * @hsync: hsync start source
232  * @hfrontporch: hfrontporch start source
233  * @htotal: htotal size source
234  */
235 struct xilinx_vtc_src_config {
236         u8 field_id_pol;
237         u8 active_chroma_pol;
238         u8 active_video_pol;
239         u8 hsync_pol;
240         u8 vsync_pol;
241         u8 hblank_pol;
242         u8 vblank_pol;
243
244         u8 vchroma;
245         u8 vactive;
246         u8 vbackporch;
247         u8 vsync;
248         u8 vfrontporch;
249         u8 vtotal;
250
251         u8 hactive;
252         u8 hbackporch;
253         u8 hsync;
254         u8 hfrontporch;
255         u8 htotal;
256 };
257
258 /* configure polarity of signals */
259 static void xilinx_vtc_config_polarity(struct xilinx_vtc *vtc,
260                                        struct xilinx_vtc_polarity *polarity)
261 {
262         u32 reg;
263
264         reg = xilinx_drm_readl(vtc->base, VTC_GPOL);
265
266         if (polarity->active_chroma)
267                 reg |= VTC_CTL_ACP;
268         if (polarity->active_video)
269                 reg |= VTC_CTL_AVP;
270         if (polarity->field_id)
271                 reg |= VTC_CTL_FIP;
272         if (polarity->vblank)
273                 reg |= VTC_CTL_VBP;
274         if (polarity->vsync)
275                 reg |= VTC_CTL_VSP;
276         if (polarity->hblank)
277                 reg |= VTC_CTL_HBP;
278         if (polarity->hsync)
279                 reg |= VTC_CTL_HSP;
280
281         xilinx_drm_writel(vtc->base, VTC_GPOL, reg);
282 }
283
284 /* configure horizontal offset */
285 static void
286 xilinx_vtc_config_hori_offset(struct xilinx_vtc *vtc,
287                               struct xilinx_vtc_hori_offset *hori_offset)
288 {
289         u32 reg;
290
291         reg = hori_offset->vblank_hori_start & VTC_XVXHOX_HSTART_MASK;
292         reg |= (hori_offset->vblank_hori_end << VTC_XVXHOX_HEND_SHIFT) &
293                VTC_XVXHOX_HEND_MASK;
294         xilinx_drm_writel(vtc->base, VTC_GVBHOFF, reg);
295
296         reg = hori_offset->vsync_hori_start & VTC_XVXHOX_HSTART_MASK;
297         reg |= (hori_offset->vsync_hori_end << VTC_XVXHOX_HEND_SHIFT) &
298                VTC_XVXHOX_HEND_MASK;
299         xilinx_drm_writel(vtc->base, VTC_GVSHOFF, reg);
300 }
301
302 /* configure source */
303 static void xilinx_vtc_config_src(struct xilinx_vtc *vtc,
304                                   struct xilinx_vtc_src_config *src_config)
305 {
306         u32 reg;
307
308         reg = xilinx_drm_readl(vtc->base, VTC_CTL);
309
310         if (src_config->field_id_pol)
311                 reg |= VTC_CTL_FIPSS;
312         if (src_config->active_chroma_pol)
313                 reg |= VTC_CTL_ACPSS;
314         if (src_config->active_video_pol)
315                 reg |= VTC_CTL_AVPSS;
316         if (src_config->hsync_pol)
317                 reg |= VTC_CTL_HSPSS;
318         if (src_config->vsync_pol)
319                 reg |= VTC_CTL_VSPSS;
320         if (src_config->hblank_pol)
321                 reg |= VTC_CTL_HBPSS;
322         if (src_config->vblank_pol)
323                 reg |= VTC_CTL_VBPSS;
324
325         if (src_config->vchroma)
326                 reg |= VTC_CTL_VCSS;
327         if (src_config->vactive)
328                 reg |= VTC_CTL_VASS;
329         if (src_config->vbackporch)
330                 reg |= VTC_CTL_VBSS;
331         if (src_config->vsync)
332                 reg |= VTC_CTL_VSSS;
333         if (src_config->vfrontporch)
334                 reg |= VTC_CTL_VFSS;
335         if (src_config->vtotal)
336                 reg |= VTC_CTL_VTSS;
337
338         if (src_config->hbackporch)
339                 reg |= VTC_CTL_HBSS;
340         if (src_config->hsync)
341                 reg |= VTC_CTL_HSSS;
342         if (src_config->hfrontporch)
343                 reg |= VTC_CTL_HFSS;
344         if (src_config->htotal)
345                 reg |= VTC_CTL_HTSS;
346
347         xilinx_drm_writel(vtc->base, VTC_CTL, reg);
348 }
349
350 /* enable vtc */
351 void xilinx_vtc_enable(struct xilinx_vtc *vtc)
352 {
353         u32 reg;
354
355         /* enable a generator only for now */
356         reg = xilinx_drm_readl(vtc->base, VTC_CTL);
357         xilinx_drm_writel(vtc->base, VTC_CTL, reg | VTC_CTL_GE);
358 }
359
360 /* disable vtc */
361 void xilinx_vtc_disable(struct xilinx_vtc *vtc)
362 {
363         u32 reg;
364
365         /* disable a generator only for now */
366         reg = xilinx_drm_readl(vtc->base, VTC_CTL);
367         xilinx_drm_writel(vtc->base, VTC_CTL, reg & ~VTC_CTL_GE);
368 }
369
370 /* configure vtc signals */
371 void xilinx_vtc_config_sig(struct xilinx_vtc *vtc,
372                            struct videomode *vm)
373 {
374         u32 reg;
375         u32 htotal, hactive, hsync_start, hbackporch_start;
376         u32 vtotal, vactive, vsync_start, vbackporch_start;
377         struct xilinx_vtc_hori_offset hori_offset;
378         struct xilinx_vtc_polarity polarity;
379         struct xilinx_vtc_src_config src;
380
381         reg = xilinx_drm_readl(vtc->base, VTC_CTL);
382         xilinx_drm_writel(vtc->base, VTC_CTL, reg & ~VTC_CTL_RU);
383
384         htotal = vm->hactive + vm->hfront_porch + vm->hsync_len +
385                  vm->hback_porch;
386         vtotal = vm->vactive + vm->vfront_porch + vm->vsync_len +
387                  vm->vback_porch;
388
389         hactive = vm->hactive;
390         vactive = vm->vactive;
391
392         hsync_start = vm->hactive + vm->hfront_porch;
393         vsync_start = vm->vactive + vm->vfront_porch;
394
395         hbackporch_start = hsync_start + vm->hsync_len;
396         vbackporch_start = vsync_start + vm->vsync_len;
397
398         reg = htotal & 0x1fff;
399         xilinx_drm_writel(vtc->base, VTC_GHSIZE, reg);
400
401         reg = vtotal & 0x1fff;
402         xilinx_drm_writel(vtc->base, VTC_GVSIZE, reg);
403
404         DRM_DEBUG_DRIVER("ht: %d, vt: %d\n", htotal, vtotal);
405
406         reg = hactive & 0x1fff;
407         reg |= (vactive & 0x1fff) << 16;
408         xilinx_drm_writel(vtc->base, VTC_GASIZE, reg);
409
410         DRM_DEBUG_DRIVER("ha: %d, va: %d\n", hactive, vactive);
411
412         reg = hsync_start & VTC_GH1_SYNCSTART_MASK;
413         reg |= (hbackporch_start << VTC_GH1_BPSTART_SHIFT) &
414                VTC_GH1_BPSTART_MASK;
415         xilinx_drm_writel(vtc->base, VTC_GHSYNC, reg);
416
417         DRM_DEBUG_DRIVER("hs: %d, hb: %d\n", hsync_start, hbackporch_start);
418
419         reg = vsync_start & VTC_GV1_SYNCSTART_MASK;
420         reg |= (vbackporch_start << VTC_GV1_BPSTART_SHIFT) &
421                VTC_GV1_BPSTART_MASK;
422         xilinx_drm_writel(vtc->base, VTC_GVSYNC, reg);
423
424         DRM_DEBUG_DRIVER("vs: %d, vb: %d\n", vsync_start, vbackporch_start);
425
426         hori_offset.vblank_hori_start = hactive;
427         hori_offset.vblank_hori_end = hactive;
428         hori_offset.vsync_hori_start = hactive;
429         hori_offset.vsync_hori_end = hactive;
430
431         xilinx_vtc_config_hori_offset(vtc, &hori_offset);
432
433         /* set up polarity */
434         memset(&polarity, 0x0, sizeof(polarity));
435         polarity.hsync = 1;
436         polarity.vsync = 1;
437         polarity.hblank = 1;
438         polarity.vblank = 1;
439         polarity.active_video = 1;
440         polarity.active_chroma = 1;
441         polarity.field_id = 1;
442         xilinx_vtc_config_polarity(vtc, &polarity);
443
444         /* set up src config */
445         memset(&src, 0x0, sizeof(src));
446         src.vchroma = 1;
447         src.vactive = 1;
448         src.vbackporch = 1;
449         src.vsync = 1;
450         src.vfrontporch = 1;
451         src.vtotal = 1;
452         src.hactive = 1;
453         src.hbackporch = 1;
454         src.hsync = 1;
455         src.hfrontporch = 1;
456         src.htotal = 1;
457         xilinx_vtc_config_src(vtc, &src);
458
459         reg = xilinx_drm_readl(vtc->base, VTC_CTL);
460         xilinx_drm_writel(vtc->base, VTC_CTL, reg | VTC_CTL_RU);
461 }
462
463 /* reset vtc */
464 void xilinx_vtc_reset(struct xilinx_vtc *vtc)
465 {
466         u32 reg;
467
468         xilinx_drm_writel(vtc->base, VTC_RESET, VTC_RESET_RESET);
469
470         /* enable register update */
471         reg = xilinx_drm_readl(vtc->base, VTC_CTL);
472         xilinx_drm_writel(vtc->base, VTC_CTL, reg | VTC_CTL_RU);
473 }
474
475 /* enable interrupt */
476 static inline void xilinx_vtc_intr_enable(struct xilinx_vtc *vtc, u32 intr)
477 {
478         xilinx_drm_writel(vtc->base, VTC_IER, (intr & VTC_IXR_ALLINTR_MASK) |
479                           xilinx_drm_readl(vtc->base, VTC_IER));
480 }
481
482 /* disable interrupt */
483 static inline void xilinx_vtc_intr_disable(struct xilinx_vtc *vtc, u32 intr)
484 {
485         xilinx_drm_writel(vtc->base, VTC_IER, ~(intr & VTC_IXR_ALLINTR_MASK) &
486                           xilinx_drm_readl(vtc->base, VTC_IER));
487 }
488
489 /* get interrupt */
490 static inline u32 xilinx_vtc_intr_get(struct xilinx_vtc *vtc)
491 {
492         return xilinx_drm_readl(vtc->base, VTC_IER) &
493                xilinx_drm_readl(vtc->base, VTC_ISR) & VTC_IXR_ALLINTR_MASK;
494 }
495
496 /* clear interrupt */
497 static inline void xilinx_vtc_intr_clear(struct xilinx_vtc *vtc, u32 intr)
498 {
499         xilinx_drm_writel(vtc->base, VTC_ISR, intr & VTC_IXR_ALLINTR_MASK);
500 }
501
502 /* interrupt handler */
503 static irqreturn_t xilinx_vtc_intr_handler(int irq, void *data)
504 {
505         struct xilinx_vtc *vtc = data;
506
507         u32 intr = xilinx_vtc_intr_get(vtc);
508
509         if (!intr)
510                 return IRQ_NONE;
511
512         if ((intr & VTC_IXR_G_VBLANK) && (vtc->vblank_fn))
513                 vtc->vblank_fn(vtc->vblank_data);
514
515         xilinx_vtc_intr_clear(vtc, intr);
516
517         return IRQ_HANDLED;
518 }
519
520 /* enable vblank interrupt */
521 void xilinx_vtc_enable_vblank_intr(struct xilinx_vtc *vtc,
522                                    void (*vblank_fn)(void *),
523                                    void *vblank_priv)
524 {
525         vtc->vblank_fn = vblank_fn;
526         vtc->vblank_data = vblank_priv;
527         xilinx_vtc_intr_enable(vtc, VTC_IXR_G_VBLANK);
528 }
529
530 /* disable vblank interrupt */
531 void xilinx_vtc_disable_vblank_intr(struct xilinx_vtc *vtc)
532 {
533         xilinx_vtc_intr_disable(vtc, VTC_IXR_G_VBLANK);
534         vtc->vblank_data = NULL;
535         vtc->vblank_fn = NULL;
536 }
537
538 static const struct of_device_id xilinx_vtc_of_match[] = {
539         { .compatible = "xlnx,v-tc-5.01.a" },
540         { /* end of table */ },
541 };
542
543 /* probe vtc */
544 struct xilinx_vtc *xilinx_vtc_probe(struct device *dev,
545                                     struct device_node *node)
546 {
547         struct xilinx_vtc *vtc;
548         const struct of_device_id *match;
549         struct resource res;
550         int ret;
551
552         match = of_match_node(xilinx_vtc_of_match, node);
553         if (!match) {
554                 dev_err(dev, "failed to match the device node\n");
555                 return ERR_PTR(-ENODEV);
556         }
557
558         vtc = devm_kzalloc(dev, sizeof(*vtc), GFP_KERNEL);
559         if (!vtc)
560                 return ERR_PTR(-ENOMEM);
561
562         ret = of_address_to_resource(node, 0, &res);
563         if (ret) {
564                 dev_err(dev, "failed to of_address_to_resource\n");
565                 return ERR_PTR(ret);
566         }
567
568         vtc->base = devm_ioremap_resource(dev, &res);
569         if (IS_ERR(vtc->base))
570                 return ERR_CAST(vtc->base);
571
572         xilinx_vtc_intr_disable(vtc, VTC_IXR_ALLINTR_MASK);
573         vtc->irq = irq_of_parse_and_map(node, 0);
574         if (vtc->irq > 0) {
575                 ret = devm_request_irq(dev, vtc->irq, xilinx_vtc_intr_handler,
576                                        IRQF_SHARED, "xilinx_vtc", vtc);
577                 if (ret) {
578                         dev_warn(dev, "failed to requet_irq() for vtc\n");
579                         return ERR_PTR(ret);
580                 }
581         }
582
583         xilinx_vtc_reset(vtc);
584
585         return vtc;
586 }