@@ -47,12 +47,17 @@ struct vc4_crtc {
47
47
const struct vc4_crtc_data * data ;
48
48
void __iomem * regs ;
49
49
50
+ /* Timestamp at start of vblank irq - unaffected by lock delays. */
51
+ ktime_t t_vblank ;
52
+
50
53
/* Which HVS channel we're using for our CRTC. */
51
54
int channel ;
52
55
53
56
u8 lut_r [256 ];
54
57
u8 lut_g [256 ];
55
58
u8 lut_b [256 ];
59
+ /* Size in pixels of the COB memory allocated to this CRTC. */
60
+ u32 cob_size ;
56
61
57
62
struct drm_pending_vblank_event * event ;
58
63
};
@@ -134,6 +139,144 @@ int vc4_crtc_debugfs_regs(struct seq_file *m, void *unused)
134
139
}
135
140
#endif
136
141
142
+ int vc4_crtc_get_scanoutpos (struct drm_device * dev , unsigned int crtc_id ,
143
+ unsigned int flags , int * vpos , int * hpos ,
144
+ ktime_t * stime , ktime_t * etime ,
145
+ const struct drm_display_mode * mode )
146
+ {
147
+ struct vc4_dev * vc4 = to_vc4_dev (dev );
148
+ struct vc4_crtc * vc4_crtc = vc4 -> crtc [crtc_id ];
149
+ u32 val ;
150
+ int fifo_lines ;
151
+ int vblank_lines ;
152
+ int ret = 0 ;
153
+
154
+ /*
155
+ * XXX Doesn't work well in interlaced mode yet, partially due
156
+ * to problems in vc4 kms or drm core interlaced mode handling,
157
+ * so disable for now in interlaced mode.
158
+ */
159
+ if (mode -> flags & DRM_MODE_FLAG_INTERLACE )
160
+ return ret ;
161
+
162
+ /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
163
+
164
+ /* Get optional system timestamp before query. */
165
+ if (stime )
166
+ * stime = ktime_get ();
167
+
168
+ /*
169
+ * Read vertical scanline which is currently composed for our
170
+ * pixelvalve by the HVS, and also the scaler status.
171
+ */
172
+ val = HVS_READ (SCALER_DISPSTATX (vc4_crtc -> channel ));
173
+
174
+ /* Get optional system timestamp after query. */
175
+ if (etime )
176
+ * etime = ktime_get ();
177
+
178
+ /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
179
+
180
+ /* Vertical position of hvs composed scanline. */
181
+ * vpos = VC4_GET_FIELD (val , SCALER_DISPSTATX_LINE );
182
+
183
+ /* No hpos info available. */
184
+ if (hpos )
185
+ * hpos = 0 ;
186
+
187
+ /* This is the offset we need for translating hvs -> pv scanout pos. */
188
+ fifo_lines = vc4_crtc -> cob_size / mode -> crtc_hdisplay ;
189
+
190
+ if (fifo_lines > 0 )
191
+ ret |= DRM_SCANOUTPOS_VALID ;
192
+
193
+ /* HVS more than fifo_lines into frame for compositing? */
194
+ if (* vpos > fifo_lines ) {
195
+ /*
196
+ * We are in active scanout and can get some meaningful results
197
+ * from HVS. The actual PV scanout can not trail behind more
198
+ * than fifo_lines as that is the fifo's capacity. Assume that
199
+ * in active scanout the HVS and PV work in lockstep wrt. HVS
200
+ * refilling the fifo and PV consuming from the fifo, ie.
201
+ * whenever the PV consumes and frees up a scanline in the
202
+ * fifo, the HVS will immediately refill it, therefore
203
+ * incrementing vpos. Therefore we choose HVS read position -
204
+ * fifo size in scanlines as a estimate of the real scanout
205
+ * position of the PV.
206
+ */
207
+ * vpos -= fifo_lines + 1 ;
208
+ if (mode -> flags & DRM_MODE_FLAG_INTERLACE )
209
+ * vpos /= 2 ;
210
+
211
+ ret |= DRM_SCANOUTPOS_ACCURATE ;
212
+ return ret ;
213
+ }
214
+
215
+ /*
216
+ * Less: This happens when we are in vblank and the HVS, after getting
217
+ * the VSTART restart signal from the PV, just started refilling its
218
+ * fifo with new lines from the top-most lines of the new framebuffers.
219
+ * The PV does not scan out in vblank, so does not remove lines from
220
+ * the fifo, so the fifo will be full quickly and the HVS has to pause.
221
+ * We can't get meaningful readings wrt. scanline position of the PV
222
+ * and need to make things up in a approximative but consistent way.
223
+ */
224
+ ret |= DRM_SCANOUTPOS_IN_VBLANK ;
225
+ vblank_lines = mode -> crtc_vtotal - mode -> crtc_vdisplay ;
226
+
227
+ if (flags & DRM_CALLED_FROM_VBLIRQ ) {
228
+ /*
229
+ * Assume the irq handler got called close to first
230
+ * line of vblank, so PV has about a full vblank
231
+ * scanlines to go, and as a base timestamp use the
232
+ * one taken at entry into vblank irq handler, so it
233
+ * is not affected by random delays due to lock
234
+ * contention on event_lock or vblank_time lock in
235
+ * the core.
236
+ */
237
+ * vpos = - vblank_lines ;
238
+
239
+ if (stime )
240
+ * stime = vc4_crtc -> t_vblank ;
241
+ if (etime )
242
+ * etime = vc4_crtc -> t_vblank ;
243
+
244
+ /*
245
+ * If the HVS fifo is not yet full then we know for certain
246
+ * we are at the very beginning of vblank, as the hvs just
247
+ * started refilling, and the stime and etime timestamps
248
+ * truly correspond to start of vblank.
249
+ */
250
+ if ((val & SCALER_DISPSTATX_FULL ) != SCALER_DISPSTATX_FULL )
251
+ ret |= DRM_SCANOUTPOS_ACCURATE ;
252
+ } else {
253
+ /*
254
+ * No clue where we are inside vblank. Return a vpos of zero,
255
+ * which will cause calling code to just return the etime
256
+ * timestamp uncorrected. At least this is no worse than the
257
+ * standard fallback.
258
+ */
259
+ * vpos = 0 ;
260
+ }
261
+
262
+ return ret ;
263
+ }
264
+
265
+ int vc4_crtc_get_vblank_timestamp (struct drm_device * dev , unsigned int crtc_id ,
266
+ int * max_error , struct timeval * vblank_time ,
267
+ unsigned flags )
268
+ {
269
+ struct vc4_dev * vc4 = to_vc4_dev (dev );
270
+ struct vc4_crtc * vc4_crtc = vc4 -> crtc [crtc_id ];
271
+ struct drm_crtc * crtc = & vc4_crtc -> base ;
272
+ struct drm_crtc_state * state = crtc -> state ;
273
+
274
+ /* Helper routine in DRM core does all the work: */
275
+ return drm_calc_vbltimestamp_from_scanoutpos (dev , crtc_id , max_error ,
276
+ vblank_time , flags ,
277
+ & state -> adjusted_mode );
278
+ }
279
+
137
280
static void vc4_crtc_destroy (struct drm_crtc * crtc )
138
281
{
139
282
drm_crtc_cleanup (crtc );
@@ -465,14 +608,6 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
465
608
466
609
WARN_ON_ONCE (dlist_next - dlist_start != vc4_state -> mm .size );
467
610
468
- HVS_WRITE (SCALER_DISPLISTX (vc4_crtc -> channel ),
469
- vc4_state -> mm .start );
470
-
471
- if (debug_dump_regs ) {
472
- DRM_INFO ("CRTC %d HVS after:\n" , drm_crtc_index (crtc ));
473
- vc4_hvs_dump_state (dev );
474
- }
475
-
476
611
if (crtc -> state -> event ) {
477
612
unsigned long flags ;
478
613
@@ -482,8 +617,20 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
482
617
483
618
spin_lock_irqsave (& dev -> event_lock , flags );
484
619
vc4_crtc -> event = crtc -> state -> event ;
485
- spin_unlock_irqrestore (& dev -> event_lock , flags );
486
620
crtc -> state -> event = NULL ;
621
+
622
+ HVS_WRITE (SCALER_DISPLISTX (vc4_crtc -> channel ),
623
+ vc4_state -> mm .start );
624
+
625
+ spin_unlock_irqrestore (& dev -> event_lock , flags );
626
+ } else {
627
+ HVS_WRITE (SCALER_DISPLISTX (vc4_crtc -> channel ),
628
+ vc4_state -> mm .start );
629
+ }
630
+
631
+ if (debug_dump_regs ) {
632
+ DRM_INFO ("CRTC %d HVS after:\n" , drm_crtc_index (crtc ));
633
+ vc4_hvs_dump_state (dev );
487
634
}
488
635
}
489
636
@@ -509,10 +656,14 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
509
656
{
510
657
struct drm_crtc * crtc = & vc4_crtc -> base ;
511
658
struct drm_device * dev = crtc -> dev ;
659
+ struct vc4_dev * vc4 = to_vc4_dev (dev );
660
+ struct vc4_crtc_state * vc4_state = to_vc4_crtc_state (crtc -> state );
661
+ u32 chan = vc4_crtc -> channel ;
512
662
unsigned long flags ;
513
663
514
664
spin_lock_irqsave (& dev -> event_lock , flags );
515
- if (vc4_crtc -> event ) {
665
+ if (vc4_crtc -> event &&
666
+ (vc4_state -> mm .start == HVS_READ (SCALER_DISPLACTX (chan )))) {
516
667
drm_crtc_send_vblank_event (crtc , vc4_crtc -> event );
517
668
vc4_crtc -> event = NULL ;
518
669
drm_crtc_vblank_put (crtc );
@@ -527,6 +678,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
527
678
irqreturn_t ret = IRQ_NONE ;
528
679
529
680
if (stat & PV_INT_VFP_START ) {
681
+ vc4_crtc -> t_vblank = ktime_get ();
530
682
CRTC_WRITE (PV_INTSTAT , PV_INT_VFP_START );
531
683
drm_crtc_handle_vblank (& vc4_crtc -> base );
532
684
vc4_crtc_handle_page_flip (vc4_crtc );
@@ -751,6 +903,22 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
751
903
}
752
904
}
753
905
906
+ static void
907
+ vc4_crtc_get_cob_allocation (struct vc4_crtc * vc4_crtc )
908
+ {
909
+ struct drm_device * drm = vc4_crtc -> base .dev ;
910
+ struct vc4_dev * vc4 = to_vc4_dev (drm );
911
+ u32 dispbase = HVS_READ (SCALER_DISPBASEX (vc4_crtc -> channel ));
912
+ /* Top/base are supposed to be 4-pixel aligned, but the
913
+ * Raspberry Pi firmware fills the low bits (which are
914
+ * presumably ignored).
915
+ */
916
+ u32 top = VC4_GET_FIELD (dispbase , SCALER_DISPBASEX_TOP ) & ~3 ;
917
+ u32 base = VC4_GET_FIELD (dispbase , SCALER_DISPBASEX_BASE ) & ~3 ;
918
+
919
+ vc4_crtc -> cob_size = top - base + 4 ;
920
+ }
921
+
754
922
static int vc4_crtc_bind (struct device * dev , struct device * master , void * data )
755
923
{
756
924
struct platform_device * pdev = to_platform_device (dev );
@@ -827,6 +995,8 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
827
995
crtc -> cursor = cursor_plane ;
828
996
}
829
997
998
+ vc4_crtc_get_cob_allocation (vc4_crtc );
999
+
830
1000
CRTC_WRITE (PV_INTEN , 0 );
831
1001
CRTC_WRITE (PV_INTSTAT , PV_INT_VFP_START );
832
1002
ret = devm_request_irq (dev , platform_get_irq (pdev , 0 ),
0 commit comments