2222#define VEC_WRITE (reg , val ) writel((val), vec->hw_base[RP1VEC_HW_BLOCK_VEC] + (reg ## _OFFSET))
2323#define VEC_READ (reg ) readl(vec->hw_base[RP1VEC_HW_BLOCK_VEC] + (reg ## _OFFSET))
2424
25- /* Experimental mode for interlace with 60fps buffer flips */
26- #define FIELD_WOBBLE
27-
2825static void rp1vec_write_regs (struct rp1_vec * vec , u32 offset , u32 const * vals , u32 num )
2926{
3027 while (num -- ) {
@@ -105,13 +102,18 @@ static const struct rp1vec_ipixfmt my_formats[] = {
105102 * See "vec_regs.h" for further descriptions of these registers and fields.
106103 * Driver should adjust some values for other TV standards and for pixel rate,
107104 * 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).
108110 */
109111
110112struct rp1vec_hwmode {
111113 u16 max_rows_per_field ; /* active lines per field (including partial ones) */
112114 u16 ref_vfp ; /* nominal (vsync_start - vdisplay) when max height */
113115 bool interlaced ; /* set for interlaced */
114- bool first_field_odd ; /* depends confusingly on line numbering convention */
116+ bool first_field_odd ; /* true if odd-indexed scanlines go to first field */
115117 s16 scale_v ; /* V scale in 2.8 format (for power-of-2 CIC rates) */
116118 s16 scale_u ; /* U scale in 2.8 format (for power-of-2 CIC rates) */
117119 u16 scale_y ; /* Y scale in 2.8 format (for power-of-2 CIC rates) */
@@ -169,31 +171,14 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
169171 .scale_luma = 0x8c9a ,
170172 .scale_sync = 0x3851 ,
171173 .scale_burst_chroma = 0x11195561 ,
172- .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 */
173175 .nco_freq = 0x087c1f07c1f07c1f ,
174- #ifdef FIELD_WOBBLE
175- /*
176- * NOTE: For the "field-wobble" interlace technique
177- * (used to achieve 60fps buffer-flip rate) to work,
178- * we had to offset the vertical timings so that VSYNC
179- * starts at half-line 0; all image line numbers are
180- * reduced by 3 compared to NTSC standard numbering.
181- * This should have no effect on the actual frame.
182- */
183176 .timing_regs = {
184177 0x03e10cc6 , 0x0d6801fb , 0x023d034c , 0x00f80b6d ,
185178 0x0207020c , 0x00000005 , 0x0006000b , 0x00070104 ,
186179 0x010e020a , 0x00000000 , 0x00000000 , 0x0119020a ,
187180 0x00120103 , 0x01040118 ,
188181 },
189- #else
190- .timing_regs = {
191- 0x03e10cc6 , 0x0d6801fb , 0x023d034c , 0x00f80b6d ,
192- 0x00000005 , 0x0006000b , 0x000c0011 , 0x000a0107 ,
193- 0x0111020d , 0x00000000 , 0x00000000 , 0x011c020d ,
194- 0x00150106 , 0x0107011b ,
195- },
196- #endif
197182 },
198183 }, {
199184 /* PAL */
@@ -235,7 +220,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
235220 .scale_luma = 0x89d8 ,
236221 .scale_sync = 0x3c00 ,
237222 .scale_burst_chroma = 0x0caf53b5 ,
238- .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 */
239224 .nco_freq = 0x0a8262b2cc48c1d1 ,
240225 .timing_regs = {
241226 0x04660cee , 0x0d8001fb , 0x025c034f , 0x00fd0b84 ,
@@ -261,7 +246,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
261246 .scale_luma = 0x89d8 ,
262247 .scale_sync = 0x3851 ,
263248 .scale_burst_chroma = 0x0d5c53b5 ,
264- .misc = 0x00091c01 , /* 5-tap FIR, SEQ_EN, 8 fld sync PAL */
249+ .misc = 0x00091c01 , /* 5-tap FIR, SEQ_EN, 8 fld sync, PAL */
265250 .nco_freq = 0x0879bbf8d6d33ea8 ,
266251 .timing_regs = {
267252 0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
@@ -284,7 +269,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
284269 .scale_luma = 0x89d8 ,
285270 .scale_sync = 0x3851 ,
286271 .scale_burst_chroma = 0x0d5c53b5 ,
287- .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 */
288273 .nco_freq = 0x0879bbf8d6d33ea8 ,
289274 .timing_regs = {
290275 0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
@@ -313,28 +298,14 @@ static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
313298 .scale_luma = 0x89d8 ,
314299 .scale_sync = 0x3c00 ,
315300 .scale_burst_chroma = 0 ,
316- .misc = 0x00084002 , /* 5-tap FIR, 2 fields, interlace */
301+ .misc = 0x00084000 , /* 5-tap FIR, 2 fields */
317302 .nco_freq = 0 ,
318- #ifdef FIELD_WOBBLE
319- /*
320- * Again we must offset the vertical timings to leave a gap
321- * between the last active line and the field/frame datum.
322- * This means the VSync sequence is banished to field end!
323- */
324303 .timing_regs = {
325304 0x06f01430 , 0x14d503cc , 0x00000000 , 0x000010de ,
326305 0x03000300 , 0x018d0194 , 0x03000300 , 0x00000000 ,
327306 0x00000000 , 0x00000000 , 0x00000000 , 0x00d50191 ,
328307 0x000a00c6 , 0x00c700d4 ,
329308 },
330- #else
331- .timing_regs = {
332- 0x06f01430 , 0x14d503cc , 0x00000000 , 0x000010de ,
333- 0x00000000 , 0x00000007 , 0x00000000 , 0x00000000 ,
334- 0x00000000 , 0x00000000 , 0x00000000 , 0x00d90195 ,
335- 0x000e00ca , 0x00cb00d8 ,
336- },
337- #endif
338309 }, {
339310 .max_rows_per_field = 369 ,
340311 .ref_vfp = 6 ,
@@ -350,7 +321,7 @@ static const struct rp1vec_hwmode rp1vec_vintage_modes[2] = {
350321 .scale_luma = 0x89d8 ,
351322 .scale_sync = 0x3b13 ,
352323 .scale_burst_chroma = 0 ,
353- .misc = 0x00084002 , /* 5-tap FIR, 2 fields, interlace */
324+ .misc = 0x00084000 , /* 5-tap FIR, 2 fields */
354325 .nco_freq = 0 ,
355326 .timing_regs = {
356327 0x03c10a08 , 0x0a4d0114 , 0x00000000 , 0x000008a6 ,
@@ -463,7 +434,12 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
463434 vpad_b = ((mode -> vsync_start - hwm -> ref_vfp ) >> (hwm -> interlaced || vec -> fake_31khz )) - h ;
464435 vpad_b = min (max (0 , vpad_b ), hwm -> max_rows_per_field - h );
465436
466- /* 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+ */
467443 VEC_WRITE (VEC_APB_TIMEOUT , 0x38 );
468444 VEC_WRITE (VEC_QOS ,
469445 BITS (VEC_QOS_DQOS , 0x0 ) |
@@ -493,12 +469,7 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
493469 BITS (VEC_MODE_VFP_EN , (vpad_b > 0 )) |
494470 BITS (VEC_MODE_VBP_EN , (hwm -> max_rows_per_field > h + vpad_b )) |
495471 BITS (VEC_MODE_HFP_EN , (hpad_r > 0 )) |
496- BITS (VEC_MODE_HBP_EN , (wmax > w + hpad_r )) |
497- #ifndef FIELD_WOBBLE /* Clear these for field-wobble! */
498- BITS (VEC_MODE_FIELDS_PER_FRAME_MINUS1 , hwm -> interlaced ) |
499- BITS (VEC_MODE_FIRST_FIELD_ODD , hwm -> first_field_odd ) |
500- #endif
501- 0 );
472+ BITS (VEC_MODE_HBP_EN , (wmax > w + hpad_r )));
502473
503474 /* Configure the hardware "back end" (in the VDAC clock domain) */
504475 VEC_WRITE (VEC_DAC_80 ,
@@ -529,9 +500,6 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
529500 VEC_WRITE (VEC_DAC_CC , (tvstd >= DRM_MODE_TV_MODE_SECAM ) ? 0 : hwm -> scale_burst_chroma );
530501 VEC_WRITE (VEC_DAC_D0 , 0x02000000 ); /* ADC offsets -- not needed in RP1? */
531502 misc = hwm -> misc ;
532- #ifdef FIELD_WOBBLE
533- misc &= ~2 ; /* For field-wobble: Clear the "fields_per_frame_minus1" flag! */
534- #endif
535503 if ((tvstd == DRM_MODE_TV_MODE_NTSC_443 || tvstd == DRM_MODE_TV_MODE_PAL ) &&
536504 mode_family != 1 ) {
537505 /* Change colour carrier frequency to 4433618.75 Hz; disable hard sync */
@@ -549,13 +517,9 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
549517 VEC_WRITE (VEC_DAC_EC , misc | rp1vec_rate_shift_table [rate - 4 ]);
550518 rp1vec_write_regs (vec , 0xDC , rp1vec_fir_regs , ARRAY_SIZE (rp1vec_fir_regs ));
551519
552- #ifdef FIELD_WOBBLE
553- vec -> interlaced = hwm -> interlaced ;
520+ /* State for software-based field flipping */
521+ vec -> field_flip = hwm -> interlaced ;
554522 vec -> lower_field_flag = hwm -> first_field_odd ;
555- #else
556- vec -> interlaced = false;
557- vec -> lower_field_flag = false;
558- #endif
559523 vec -> last_dma_addr = 0 ;
560524
561525 /* Set up interrupts and initialise VEC. It will start on the next rp1vec_hw_update() */
@@ -576,19 +540,20 @@ void rp1vec_hw_update(struct rp1_vec *vec, dma_addr_t addr, u32 offset, u32 stri
576540{
577541 unsigned long flags ;
578542
579- spin_lock_irqsave ( & vec -> hw_lock , flags ) ;
543+ addr += offset ;
580544
581545 /*
582546 * Update STRIDE, DMAH and DMAL only. When called after rp1vec_hw_setup(),
583547 * DMA starts immediately; if already running, the buffer will flip at
584- * the next vertical sync event. In interlaced mode, we need to adjust
585- * the address and stride to display only the current field, saving
586- * the original address (so it can be flipped for subsequent fields).
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).
587551 */
588- addr += offset ;
552+ spin_lock_irqsave (& vec -> hw_lock , flags );
553+
589554 vec -> last_dma_addr = addr ;
590555 vec -> last_stride = stride ;
591- if (vec -> fake_31khz || vec -> interlaced ) {
556+ if (vec -> field_flip || vec -> fake_31khz ) {
592557 if (vec -> fake_31khz || vec -> lower_field_flag )
593558 addr += stride ;
594559 stride *= 2 ;
@@ -624,11 +589,9 @@ void rp1vec_hw_stop(struct rp1_vec *vec)
624589void rp1vec_hw_vblank_ctrl (struct rp1_vec * vec , int enable )
625590{
626591 VEC_WRITE (VEC_IRQ_ENABLES ,
627- BITS (VEC_IRQ_ENABLES_DONE , 1 ) |
628- BITS (VEC_IRQ_ENABLES_DMA , (enable ? 1 : 0 )) |
629- #ifdef FIELD_WOBBLE
630- BITS (VEC_IRQ_ENABLES_MATCH , vec -> interlaced ) |
631- #endif
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 ) |
632595 BITS (VEC_IRQ_ENABLES_MATCH_ROW , 32 ));
633596}
634597
@@ -644,14 +607,13 @@ irqreturn_t rp1vec_hw_isr(int irq, void *dev)
644607 if (u & VEC_IRQ_FLAGS_DONE_BITS )
645608 complete (& vec -> finished );
646609
647- #ifdef FIELD_WOBBLE
648610 /*
649611 * VEC has native support for interlaced modes, but that only
650612 * supports buffer-flips per frame (30fps), not field (60fps).
651613 * Instead, we always run the VEC front end in a "progressive"
652- * mode and use the "field-wobble " trick (see RP1 DPI driver).
614+ * mode and use the "field-flip " trick (see RP1 DPI driver).
653615 */
654- if ((u & VEC_IRQ_FLAGS_MATCH_BITS ) && vec -> interlaced ) {
616+ if ((u & VEC_IRQ_FLAGS_MATCH_BITS ) && vec -> field_flip ) {
655617 unsigned long flags ;
656618 dma_addr_t a ;
657619
@@ -666,7 +628,6 @@ irqreturn_t rp1vec_hw_isr(int irq, void *dev)
666628 }
667629 spin_unlock_irqrestore (& vec -> hw_lock , flags );
668630 }
669- #endif
670631 }
671632
672633 return u ? IRQ_HANDLED : IRQ_NONE ;
0 commit comments