@@ -68,6 +68,8 @@ struct decon_context {
6868 unsigned long flags ;
6969 unsigned long out_type ;
7070 int first_win ;
71+ spinlock_t vblank_lock ;
72+ u32 frame_id ;
7173};
7274
7375static const uint32_t decon_formats [] = {
@@ -103,7 +105,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
103105 if (ctx -> out_type & IFTYPE_I80 )
104106 val |= VIDINTCON0_FRAMEDONE ;
105107 else
106- val |= VIDINTCON0_INTFRMEN ;
108+ val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP ;
107109
108110 writel (val , ctx -> addr + DECON_VIDINTCON0 );
109111 }
@@ -122,14 +124,56 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
122124 writel (0 , ctx -> addr + DECON_VIDINTCON0 );
123125}
124126
127+ /* return number of starts/ends of frame transmissions since reset */
128+ static u32 decon_get_frame_count (struct decon_context * ctx , bool end )
129+ {
130+ u32 frm , pfrm , status , cnt = 2 ;
131+
132+ /* To get consistent result repeat read until frame id is stable.
133+ * Usually the loop will be executed once, in rare cases when the loop
134+ * is executed at frame change time 2nd pass will be needed.
135+ */
136+ frm = readl (ctx -> addr + DECON_CRFMID );
137+ do {
138+ status = readl (ctx -> addr + DECON_VIDCON1 );
139+ pfrm = frm ;
140+ frm = readl (ctx -> addr + DECON_CRFMID );
141+ } while (frm != pfrm && -- cnt );
142+
143+ /* CRFMID is incremented on BPORCH in case of I80 and on VSYNC in case
144+ * of RGB, it should be taken into account.
145+ */
146+ if (!frm )
147+ return 0 ;
148+
149+ switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE )) {
150+ case VIDCON1_VSTATUS_VS :
151+ if (!(ctx -> out_type & IFTYPE_I80 ))
152+ -- frm ;
153+ break ;
154+ case VIDCON1_VSTATUS_BP :
155+ -- frm ;
156+ break ;
157+ case VIDCON1_I80_ACTIVE :
158+ case VIDCON1_VSTATUS_AC :
159+ if (end )
160+ -- frm ;
161+ break ;
162+ default :
163+ break ;
164+ }
165+
166+ return frm ;
167+ }
168+
125169static void decon_setup_trigger (struct decon_context * ctx )
126170{
127171 if (!(ctx -> out_type & (IFTYPE_I80 | I80_HW_TRG )))
128172 return ;
129173
130174 if (!(ctx -> out_type & I80_HW_TRG )) {
131- writel (TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
132- | TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN ,
175+ writel (TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
176+ TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN ,
133177 ctx -> addr + DECON_TRIGCON );
134178 return ;
135179 }
@@ -365,11 +409,14 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
365409static void decon_atomic_flush (struct exynos_drm_crtc * crtc )
366410{
367411 struct decon_context * ctx = crtc -> ctx ;
412+ unsigned long flags ;
368413 int i ;
369414
370415 if (test_bit (BIT_SUSPENDED , & ctx -> flags ))
371416 return ;
372417
418+ spin_lock_irqsave (& ctx -> vblank_lock , flags );
419+
373420 for (i = ctx -> first_win ; i < WINDOWS_NR ; i ++ )
374421 decon_shadow_protect_win (ctx , i , false);
375422
@@ -378,11 +425,18 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
378425
379426 if (ctx -> out_type & IFTYPE_I80 )
380427 set_bit (BIT_WIN_UPDATED , & ctx -> flags );
428+
429+ ctx -> frame_id = decon_get_frame_count (ctx , true);
430+
431+ exynos_crtc_handle_event (crtc );
432+
433+ spin_unlock_irqrestore (& ctx -> vblank_lock , flags );
381434}
382435
383436static void decon_swreset (struct decon_context * ctx )
384437{
385438 unsigned int tries ;
439+ unsigned long flags ;
386440
387441 writel (0 , ctx -> addr + DECON_VIDCON0 );
388442 for (tries = 2000 ; tries ; -- tries ) {
@@ -400,6 +454,10 @@ static void decon_swreset(struct decon_context *ctx)
400454
401455 WARN (tries == 0 , "failed to software reset DECON\n" );
402456
457+ spin_lock_irqsave (& ctx -> vblank_lock , flags );
458+ ctx -> frame_id = 0 ;
459+ spin_unlock_irqrestore (& ctx -> vblank_lock , flags );
460+
403461 if (!(ctx -> out_type & IFTYPE_HDMI ))
404462 return ;
405463
@@ -578,6 +636,24 @@ static const struct component_ops decon_component_ops = {
578636 .unbind = decon_unbind ,
579637};
580638
639+ static void decon_handle_vblank (struct decon_context * ctx )
640+ {
641+ u32 frm ;
642+
643+ spin_lock (& ctx -> vblank_lock );
644+
645+ frm = decon_get_frame_count (ctx , true);
646+
647+ if (frm != ctx -> frame_id ) {
648+ /* handle only if incremented, take care of wrap-around */
649+ if ((s32 )(frm - ctx -> frame_id ) > 0 )
650+ drm_crtc_handle_vblank (& ctx -> crtc -> base );
651+ ctx -> frame_id = frm ;
652+ }
653+
654+ spin_unlock (& ctx -> vblank_lock );
655+ }
656+
581657static irqreturn_t decon_irq_handler (int irq , void * dev_id )
582658{
583659 struct decon_context * ctx = dev_id ;
@@ -598,7 +674,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
598674 (VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F ))
599675 return IRQ_HANDLED ;
600676 }
601- drm_crtc_handle_vblank ( & ctx -> crtc -> base );
677+ decon_handle_vblank ( ctx );
602678 }
603679
604680out :
@@ -671,14 +747,15 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
671747 __set_bit (BIT_SUSPENDED , & ctx -> flags );
672748 ctx -> dev = dev ;
673749 ctx -> out_type = (unsigned long )of_device_get_match_data (dev );
750+ spin_lock_init (& ctx -> vblank_lock );
674751
675752 if (ctx -> out_type & IFTYPE_HDMI ) {
676753 ctx -> first_win = 1 ;
677754 } else if (of_get_child_by_name (dev -> of_node , "i80-if-timings" )) {
678755 ctx -> out_type |= IFTYPE_I80 ;
679756 }
680757
681- if (ctx -> out_type | I80_HW_TRG ) {
758+ if (ctx -> out_type & I80_HW_TRG ) {
682759 ctx -> sysreg = syscon_regmap_lookup_by_phandle (dev -> of_node ,
683760 "samsung,disp-sysreg" );
684761 if (IS_ERR (ctx -> sysreg )) {
0 commit comments