@@ -102,13 +102,18 @@ static const struct rp1vec_ipixfmt my_formats[] = {
102
102
* See "vec_regs.h" for further descriptions of these registers and fields.
103
103
* Driver should adjust some values for other TV standards and for pixel rate,
104
104
* and must ensure that ((de_end - de_bgn) % rate) == 0.
105
+ *
106
+ * To support 60fps update in interlaced modes, we now do ISR-based field-flip.
107
+ * The FIELDS_PER_FRAME_MINUS1 flag in "misc" is no longer set. Some vertical
108
+ * timings have been rotated wrt conventional line-numbering (to ensure a gap
109
+ * between the last active line and nominal end-of-field).
105
110
*/
106
111
107
112
struct rp1vec_hwmode {
108
113
u16 max_rows_per_field ; /* active lines per field (including partial ones) */
109
114
u16 ref_vfp ; /* nominal (vsync_start - vdisplay) when max height */
110
115
bool interlaced ; /* set for interlaced */
111
- bool first_field_odd ; /* depends confusingly on line numbering convention */
116
+ bool first_field_odd ; /* true if odd-indexed scanlines go to first field */
112
117
s16 scale_v ; /* V scale in 2.8 format (for power-of-2 CIC rates) */
113
118
s16 scale_u ; /* U scale in 2.8 format (for power-of-2 CIC rates) */
114
119
u16 scale_y ; /* Y scale in 2.8 format (for power-of-2 CIC rates) */
@@ -166,13 +171,13 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
166
171
.scale_luma = 0x8c9a ,
167
172
.scale_sync = 0x3851 ,
168
173
.scale_burst_chroma = 0x11195561 ,
169
- .misc = 0x00094c02 , /* 5-tap FIR, SEQ_EN, 2 flds, 4 fld sync, ilace */
174
+ .misc = 0x00094c00 , /* 5-tap FIR, SEQ_EN, 2 flds, 4 fld sync */
170
175
.nco_freq = 0x087c1f07c1f07c1f ,
171
176
.timing_regs = {
172
177
0x03e10cc6 , 0x0d6801fb , 0x023d034c , 0x00f80b6d ,
173
- 0x00000005 , 0x0006000b , 0x000c0011 , 0x000a0107 ,
174
- 0x0111020d , 0x00000000 , 0x00000000 , 0x011c020d ,
175
- 0x00150106 , 0x0107011b ,
178
+ 0x0207020c , 0x00000005 , 0x0006000b , 0x00070104 ,
179
+ 0x010e020a , 0x00000000 , 0x00000000 , 0x0119020a ,
180
+ 0x00120103 , 0x01040118 ,
176
181
},
177
182
},
178
183
}, {
@@ -215,7 +220,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
215
220
.scale_luma = 0x89d8 ,
216
221
.scale_sync = 0x3c00 ,
217
222
.scale_burst_chroma = 0x0caf53b5 ,
218
- .misc = 0x0009dc03 , /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, ilace , PAL */
223
+ .misc = 0x0009dc01 , /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, PAL */
219
224
.nco_freq = 0x0a8262b2cc48c1d1 ,
220
225
.timing_regs = {
221
226
0x04660cee , 0x0d8001fb , 0x025c034f , 0x00fd0b84 ,
@@ -241,7 +246,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
241
246
.scale_luma = 0x89d8 ,
242
247
.scale_sync = 0x3851 ,
243
248
.scale_burst_chroma = 0x0d5c53b5 ,
244
- .misc = 0x00091c01 , /* 5-tap FIR, SEQ_EN, 8 fld sync PAL */
249
+ .misc = 0x00091c01 , /* 5-tap FIR, SEQ_EN, 8 fld sync, PAL */
245
250
.nco_freq = 0x0879bbf8d6d33ea8 ,
246
251
.timing_regs = {
247
252
0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
@@ -264,11 +269,11 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
264
269
.scale_luma = 0x89d8 ,
265
270
.scale_sync = 0x3851 ,
266
271
.scale_burst_chroma = 0x0d5c53b5 ,
267
- .misc = 0x0009dc03 , /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, ilace , PAL */
272
+ .misc = 0x0009dc01 , /* 5-tap FIR, SEQ_EN, 4 flds, 8 fld sync, PAL */
268
273
.nco_freq = 0x0879bbf8d6d33ea8 ,
269
274
.timing_regs = {
270
275
0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
271
- 0x00140019 , 0x00000005 , 0x0006000b , 0x00090103 ,
276
+ 0x0207020c , 0x00000005 , 0x0006000b , 0x00090103 ,
272
277
0x010f0209 , 0x00080102 , 0x010e020a , 0x0119020a ,
273
278
0x00120103 , 0x01040118 ,
274
279
},
@@ -293,13 +298,13 @@ static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
293
298
.scale_luma = 0x89d8 ,
294
299
.scale_sync = 0x3c00 ,
295
300
.scale_burst_chroma = 0 ,
296
- .misc = 0x00084002 , /* 5-tap FIR, 2 fields, interlace */
301
+ .misc = 0x00084000 , /* 5-tap FIR, 2 fields */
297
302
.nco_freq = 0 ,
298
303
.timing_regs = {
299
304
0x06f01430 , 0x14d503cc , 0x00000000 , 0x000010de ,
300
- 0x00000000 , 0x00000007 , 0x00000000 , 0x00000000 ,
301
- 0x00000000 , 0x00000000 , 0x00000000 , 0x00d90195 ,
302
- 0x000e00ca , 0x00cb00d8 ,
305
+ 0x03000300 , 0x018d0194 , 0x03000300 , 0x00000000 ,
306
+ 0x00000000 , 0x00000000 , 0x00000000 , 0x00d50191 ,
307
+ 0x000a00c6 , 0x00c700d4 ,
303
308
},
304
309
}, {
305
310
.max_rows_per_field = 369 ,
@@ -316,7 +321,7 @@ static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
316
321
.scale_luma = 0x89d8 ,
317
322
.scale_sync = 0x3b13 ,
318
323
.scale_burst_chroma = 0 ,
319
- .misc = 0x00084002 , /* 5-tap FIR, 2 fields, interlace */
324
+ .misc = 0x00084000 , /* 5-tap FIR, 2 fields */
320
325
.nco_freq = 0 ,
321
326
.timing_regs = {
322
327
0x03c10a08 , 0x0a4d0114 , 0x00000000 , 0x000008a6 ,
@@ -429,7 +434,12 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
429
434
vpad_b = ((mode -> vsync_start - hwm -> ref_vfp ) >> (hwm -> interlaced || vec -> fake_31khz )) - h ;
430
435
vpad_b = min (max (0 , vpad_b ), hwm -> max_rows_per_field - h );
431
436
432
- /* Configure the hardware "front end" (in the sysclock domain) */
437
+ /*
438
+ * Configure the hardware "front end" (in the sysclock domain).
439
+ * Note: To support 60fps update (per-field buffer flips), we no longer
440
+ * enable VEC's native interlaced mode (which can't flip in mid-frame).
441
+ * Instead, send individual fields, using software to flip between them.
442
+ */
433
443
VEC_WRITE (VEC_APB_TIMEOUT , 0x38 );
434
444
VEC_WRITE (VEC_QOS ,
435
445
BITS (VEC_QOS_DQOS , 0x0 ) |
@@ -459,9 +469,7 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
459
469
BITS (VEC_MODE_VFP_EN , (vpad_b > 0 )) |
460
470
BITS (VEC_MODE_VBP_EN , (hwm -> max_rows_per_field > h + vpad_b )) |
461
471
BITS (VEC_MODE_HFP_EN , (hpad_r > 0 )) |
462
- BITS (VEC_MODE_HBP_EN , (wmax > w + hpad_r )) |
463
- BITS (VEC_MODE_FIELDS_PER_FRAME_MINUS1 , hwm -> interlaced ) |
464
- BITS (VEC_MODE_FIRST_FIELD_ODD , hwm -> first_field_odd ));
472
+ BITS (VEC_MODE_HBP_EN , (wmax > w + hpad_r )));
465
473
466
474
/* Configure the hardware "back end" (in the VDAC clock domain) */
467
475
VEC_WRITE (VEC_DAC_80 ,
@@ -509,6 +517,11 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
509
517
VEC_WRITE (VEC_DAC_EC , misc | rp1vec_rate_shift_table [rate - 4 ]);
510
518
rp1vec_write_regs (vec , 0xDC , rp1vec_fir_regs , ARRAY_SIZE (rp1vec_fir_regs ));
511
519
520
+ /* State for software-based field flipping */
521
+ vec -> field_flip = hwm -> interlaced ;
522
+ vec -> lower_field_flag = hwm -> first_field_odd ;
523
+ vec -> last_dma_addr = 0 ;
524
+
512
525
/* Set up interrupts and initialise VEC. It will start on the next rp1vec_hw_update() */
513
526
VEC_WRITE (VEC_IRQ_FLAGS , 0xFFFFFFFFu );
514
527
rp1vec_hw_vblank_ctrl (vec , 1 );
@@ -525,32 +538,49 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
525
538
526
539
void rp1vec_hw_update (struct rp1_vec * vec , dma_addr_t addr , u32 offset , u32 stride )
527
540
{
541
+ unsigned long flags ;
542
+
543
+ addr += offset ;
544
+
528
545
/*
529
546
* Update STRIDE, DMAH and DMAL only. When called after rp1vec_hw_setup(),
530
547
* DMA starts immediately; if already running, the buffer will flip at
531
- * the next vertical sync event.
548
+ * the next vertical sync event. For field-rate update in interlaced modes,
549
+ * we need to adjust the address and stride to display the current field,
550
+ * saving the original address (so it can be flipped for subsequent fields).
532
551
*/
533
- u64 a = addr + offset ;
552
+ spin_lock_irqsave ( & vec -> hw_lock , flags ) ;
534
553
535
- if (vec -> fake_31khz ) {
536
- a += stride ;
554
+ vec -> last_dma_addr = addr ;
555
+ vec -> last_stride = stride ;
556
+ if (vec -> field_flip || vec -> fake_31khz ) {
557
+ if (vec -> fake_31khz || vec -> lower_field_flag )
558
+ addr += stride ;
537
559
stride *= 2 ;
538
560
}
539
561
VEC_WRITE (VEC_DMA_STRIDE , stride );
540
- VEC_WRITE (VEC_DMA_ADDR_H , a >> 32 );
541
- VEC_WRITE (VEC_DMA_ADDR_L , a & 0xFFFFFFFFu );
562
+ VEC_WRITE (VEC_DMA_ADDR_H , addr >> 32 );
563
+ VEC_WRITE (VEC_DMA_ADDR_L , addr & 0xFFFFFFFFu );
564
+
565
+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
542
566
}
543
567
544
568
void rp1vec_hw_stop (struct rp1_vec * vec )
545
569
{
570
+ unsigned long flags ;
571
+
546
572
/*
547
573
* Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for
548
574
* the current and any queued frame to end. "Force drain" flags are not used,
549
575
* as they seem to prevent DMA from re-starting properly; it's safer to wait.
550
576
*/
551
577
578
+ spin_lock_irqsave (& vec -> hw_lock , flags );
579
+ vec -> last_dma_addr = 0 ;
552
580
reinit_completion (& vec -> finished );
553
581
VEC_WRITE (VEC_CONTROL , 0 );
582
+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
583
+
554
584
if (!wait_for_completion_timeout (& vec -> finished , HZ / 10 ))
555
585
drm_err (& vec -> drm , "%s: timed out waiting for idle\n" , __func__ );
556
586
VEC_WRITE (VEC_IRQ_ENABLES , 0 );
@@ -559,9 +589,10 @@ void rp1vec_hw_stop(struct rp1_vec *vec)
559
589
void rp1vec_hw_vblank_ctrl (struct rp1_vec * vec , int enable )
560
590
{
561
591
VEC_WRITE (VEC_IRQ_ENABLES ,
562
- BITS (VEC_IRQ_ENABLES_DONE , 1 ) |
563
- BITS (VEC_IRQ_ENABLES_DMA , (enable ? 1 : 0 )) |
564
- BITS (VEC_IRQ_ENABLES_MATCH_ROW , 1023 ));
592
+ BITS (VEC_IRQ_ENABLES_DONE , 1 ) |
593
+ BITS (VEC_IRQ_ENABLES_DMA , (enable ? 1 : 0 )) |
594
+ BITS (VEC_IRQ_ENABLES_MATCH , vec -> field_flip ) |
595
+ BITS (VEC_IRQ_ENABLES_MATCH_ROW , 32 ));
565
596
}
566
597
567
598
irqreturn_t rp1vec_hw_isr (int irq , void * dev )
@@ -575,6 +606,29 @@ irqreturn_t rp1vec_hw_isr(int irq, void *dev)
575
606
drm_crtc_handle_vblank (& vec -> pipe .crtc );
576
607
if (u & VEC_IRQ_FLAGS_DONE_BITS )
577
608
complete (& vec -> finished );
609
+
610
+ /*
611
+ * VEC has native support for interlaced modes, but that only
612
+ * supports buffer-flips per frame (30fps), not field (60fps).
613
+ * Instead, we always run the VEC front end in a "progressive"
614
+ * mode and use the "field-flip" trick (see RP1 DPI driver).
615
+ */
616
+ if ((u & VEC_IRQ_FLAGS_MATCH_BITS ) && vec -> field_flip ) {
617
+ unsigned long flags ;
618
+ dma_addr_t a ;
619
+
620
+ spin_lock_irqsave (& vec -> hw_lock , flags );
621
+ vec -> lower_field_flag = !vec -> lower_field_flag ;
622
+ a = vec -> last_dma_addr ;
623
+ if (a ) {
624
+ if (vec -> lower_field_flag )
625
+ a += vec -> last_stride ;
626
+ VEC_WRITE (VEC_DMA_ADDR_H , a >> 32 );
627
+ VEC_WRITE (VEC_DMA_ADDR_L , a & 0xFFFFFFFFu );
628
+ }
629
+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
630
+ }
578
631
}
632
+
579
633
return u ? IRQ_HANDLED : IRQ_NONE ;
580
634
}
0 commit comments