@@ -102,13 +102,18 @@ static const struct rp1vec_ipixfmt my_formats[] = {
102102 * See "vec_regs.h" for further descriptions of these registers and fields.
103103 * Driver should adjust some values for other TV standards and for pixel rate,
104104 * 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).
105110 */
106111
107112struct rp1vec_hwmode {
108113 u16 max_rows_per_field ; /* active lines per field (including partial ones) */
109114 u16 ref_vfp ; /* nominal (vsync_start - vdisplay) when max height */
110115 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 */
112117 s16 scale_v ; /* V scale in 2.8 format (for power-of-2 CIC rates) */
113118 s16 scale_u ; /* U scale in 2.8 format (for power-of-2 CIC rates) */
114119 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] = {
166171 .scale_luma = 0x8c9a ,
167172 .scale_sync = 0x3851 ,
168173 .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 */
170175 .nco_freq = 0x087c1f07c1f07c1f ,
171176 .timing_regs = {
172177 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 ,
176181 },
177182 },
178183 }, {
@@ -215,7 +220,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
215220 .scale_luma = 0x89d8 ,
216221 .scale_sync = 0x3c00 ,
217222 .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 */
219224 .nco_freq = 0x0a8262b2cc48c1d1 ,
220225 .timing_regs = {
221226 0x04660cee , 0x0d8001fb , 0x025c034f , 0x00fd0b84 ,
@@ -241,7 +246,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
241246 .scale_luma = 0x89d8 ,
242247 .scale_sync = 0x3851 ,
243248 .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 */
245250 .nco_freq = 0x0879bbf8d6d33ea8 ,
246251 .timing_regs = {
247252 0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
@@ -264,11 +269,11 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
264269 .scale_luma = 0x89d8 ,
265270 .scale_sync = 0x3851 ,
266271 .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 */
268273 .nco_freq = 0x0879bbf8d6d33ea8 ,
269274 .timing_regs = {
270275 0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
271- 0x00140019 , 0x00000005 , 0x0006000b , 0x00090103 ,
276+ 0x0207020c , 0x00000005 , 0x0006000b , 0x00090103 ,
272277 0x010f0209 , 0x00080102 , 0x010e020a , 0x0119020a ,
273278 0x00120103 , 0x01040118 ,
274279 },
@@ -293,13 +298,13 @@ static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
293298 .scale_luma = 0x89d8 ,
294299 .scale_sync = 0x3c00 ,
295300 .scale_burst_chroma = 0 ,
296- .misc = 0x00084002 , /* 5-tap FIR, 2 fields, interlace */
301+ .misc = 0x00084000 , /* 5-tap FIR, 2 fields */
297302 .nco_freq = 0 ,
298303 .timing_regs = {
299304 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 ,
303308 },
304309 }, {
305310 .max_rows_per_field = 369 ,
@@ -316,7 +321,7 @@ static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
316321 .scale_luma = 0x89d8 ,
317322 .scale_sync = 0x3b13 ,
318323 .scale_burst_chroma = 0 ,
319- .misc = 0x00084002 , /* 5-tap FIR, 2 fields, interlace */
324+ .misc = 0x00084000 , /* 5-tap FIR, 2 fields */
320325 .nco_freq = 0 ,
321326 .timing_regs = {
322327 0x03c10a08 , 0x0a4d0114 , 0x00000000 , 0x000008a6 ,
@@ -429,7 +434,12 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
429434 vpad_b = ((mode -> vsync_start - hwm -> ref_vfp ) >> (hwm -> interlaced || vec -> fake_31khz )) - h ;
430435 vpad_b = min (max (0 , vpad_b ), hwm -> max_rows_per_field - h );
431436
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+ */
433443 VEC_WRITE (VEC_APB_TIMEOUT , 0x38 );
434444 VEC_WRITE (VEC_QOS ,
435445 BITS (VEC_QOS_DQOS , 0x0 ) |
@@ -459,9 +469,7 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
459469 BITS (VEC_MODE_VFP_EN , (vpad_b > 0 )) |
460470 BITS (VEC_MODE_VBP_EN , (hwm -> max_rows_per_field > h + vpad_b )) |
461471 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 )));
465473
466474 /* Configure the hardware "back end" (in the VDAC clock domain) */
467475 VEC_WRITE (VEC_DAC_80 ,
@@ -509,6 +517,11 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
509517 VEC_WRITE (VEC_DAC_EC , misc | rp1vec_rate_shift_table [rate - 4 ]);
510518 rp1vec_write_regs (vec , 0xDC , rp1vec_fir_regs , ARRAY_SIZE (rp1vec_fir_regs ));
511519
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+
512525 /* Set up interrupts and initialise VEC. It will start on the next rp1vec_hw_update() */
513526 VEC_WRITE (VEC_IRQ_FLAGS , 0xFFFFFFFFu );
514527 rp1vec_hw_vblank_ctrl (vec , 1 );
@@ -525,32 +538,49 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
525538
526539void rp1vec_hw_update (struct rp1_vec * vec , dma_addr_t addr , u32 offset , u32 stride )
527540{
541+ unsigned long flags ;
542+
543+ addr += offset ;
544+
528545 /*
529546 * Update STRIDE, DMAH and DMAL only. When called after rp1vec_hw_setup(),
530547 * 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).
532551 */
533- u64 a = addr + offset ;
552+ spin_lock_irqsave ( & vec -> hw_lock , flags ) ;
534553
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 ;
537559 stride *= 2 ;
538560 }
539561 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 );
542566}
543567
544568void rp1vec_hw_stop (struct rp1_vec * vec )
545569{
570+ unsigned long flags ;
571+
546572 /*
547573 * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for
548574 * the current and any queued frame to end. "Force drain" flags are not used,
549575 * as they seem to prevent DMA from re-starting properly; it's safer to wait.
550576 */
551577
578+ spin_lock_irqsave (& vec -> hw_lock , flags );
579+ vec -> last_dma_addr = 0 ;
552580 reinit_completion (& vec -> finished );
553581 VEC_WRITE (VEC_CONTROL , 0 );
582+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
583+
554584 if (!wait_for_completion_timeout (& vec -> finished , HZ / 10 ))
555585 drm_err (& vec -> drm , "%s: timed out waiting for idle\n" , __func__ );
556586 VEC_WRITE (VEC_IRQ_ENABLES , 0 );
@@ -559,9 +589,10 @@ void rp1vec_hw_stop(struct rp1_vec *vec)
559589void rp1vec_hw_vblank_ctrl (struct rp1_vec * vec , int enable )
560590{
561591 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 ));
565596}
566597
567598irqreturn_t rp1vec_hw_isr (int irq , void * dev )
@@ -575,6 +606,29 @@ irqreturn_t rp1vec_hw_isr(int irq, void *dev)
575606 drm_crtc_handle_vblank (& vec -> pipe .crtc );
576607 if (u & VEC_IRQ_FLAGS_DONE_BITS )
577608 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+ }
578631 }
632+
579633 return u ? IRQ_HANDLED : IRQ_NONE ;
580634}
0 commit comments