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