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+
2528static void rp1vec_write_regs (struct rp1_vec * vec , u32 offset , u32 const * vals , u32 num )
2629{
2730 while (num -- ) {
@@ -168,12 +171,29 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
168171 .scale_burst_chroma = 0x11195561 ,
169172 .misc = 0x00094c02 , /* 5-tap FIR, SEQ_EN, 2 flds, 4 fld sync, ilace */
170173 .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+ */
183+ .timing_regs = {
184+ 0x03e10cc6 , 0x0d6801fb , 0x023d034c , 0x00f80b6d ,
185+ 0x0207020c , 0x00000005 , 0x0006000b , 0x00070104 ,
186+ 0x010e020a , 0x00000000 , 0x00000000 , 0x0119020a ,
187+ 0x00120103 , 0x01040118 ,
188+ },
189+ #else
171190 .timing_regs = {
172191 0x03e10cc6 , 0x0d6801fb , 0x023d034c , 0x00f80b6d ,
173192 0x00000005 , 0x0006000b , 0x000c0011 , 0x000a0107 ,
174193 0x0111020d , 0x00000000 , 0x00000000 , 0x011c020d ,
175194 0x00150106 , 0x0107011b ,
176195 },
196+ #endif
177197 },
178198 }, {
179199 /* PAL */
@@ -268,7 +288,7 @@ static const struct rp1vec_hwmode rp1vec_hwmodes[3][2] = {
268288 .nco_freq = 0x0879bbf8d6d33ea8 ,
269289 .timing_regs = {
270290 0x03e10cc6 , 0x0d6801fb , 0x023c034c , 0x00f80b6e ,
271- 0x00140019 , 0x00000005 , 0x0006000b , 0x00090103 ,
291+ 0x00140019 , 0x00000005 , 0x0006000b , 0x00090103 , // XXX [0x94] looks dodgy to me?
272292 0x010f0209 , 0x00080102 , 0x010e020a , 0x0119020a ,
273293 0x00120103 , 0x01040118 ,
274294 },
@@ -460,8 +480,11 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
460480 BITS (VEC_MODE_VBP_EN , (hwm -> max_rows_per_field > h + vpad_b )) |
461481 BITS (VEC_MODE_HFP_EN , (hpad_r > 0 )) |
462482 BITS (VEC_MODE_HBP_EN , (wmax > w + hpad_r )) |
483+ #ifndef FIELD_WOBBLE /* Clear these for field-wobble! */
463484 BITS (VEC_MODE_FIELDS_PER_FRAME_MINUS1 , hwm -> interlaced ) |
464- BITS (VEC_MODE_FIRST_FIELD_ODD , hwm -> first_field_odd ));
485+ BITS (VEC_MODE_FIRST_FIELD_ODD , hwm -> first_field_odd ) |
486+ #endif
487+ 0 );
465488
466489 /* Configure the hardware "back end" (in the VDAC clock domain) */
467490 VEC_WRITE (VEC_DAC_80 ,
@@ -492,6 +515,9 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
492515 VEC_WRITE (VEC_DAC_CC , (tvstd >= DRM_MODE_TV_MODE_SECAM ) ? 0 : hwm -> scale_burst_chroma );
493516 VEC_WRITE (VEC_DAC_D0 , 0x02000000 ); /* ADC offsets -- not needed in RP1? */
494517 misc = hwm -> misc ;
518+ #ifdef FIELD_WOBBLE
519+ misc &= ~2 ; /* For field-wobble: Clear the "fields_per_frame_minus1" flag! */
520+ #endif
495521 if ((tvstd == DRM_MODE_TV_MODE_NTSC_443 || tvstd == DRM_MODE_TV_MODE_PAL ) &&
496522 mode_family != 1 ) {
497523 /* Change colour carrier frequency to 4433618.75 Hz; disable hard sync */
@@ -509,6 +535,15 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
509535 VEC_WRITE (VEC_DAC_EC , misc | rp1vec_rate_shift_table [rate - 4 ]);
510536 rp1vec_write_regs (vec , 0xDC , rp1vec_fir_regs , ARRAY_SIZE (rp1vec_fir_regs ));
511537
538+ #ifdef FIELD_WOBBLE
539+ vec -> interlaced = hwm -> interlaced ;
540+ vec -> lower_field_flag = hwm -> first_field_odd ;
541+ #else
542+ vec -> interlaced = false;
543+ vec -> lower_field_flag = false;
544+ #endif
545+ vec -> last_dma_addr = 0 ;
546+
512547 /* Set up interrupts and initialise VEC. It will start on the next rp1vec_hw_update() */
513548 VEC_WRITE (VEC_IRQ_FLAGS , 0xFFFFFFFFu );
514549 rp1vec_hw_vblank_ctrl (vec , 1 );
@@ -525,32 +560,48 @@ void rp1vec_hw_setup(struct rp1_vec *vec,
525560
526561void rp1vec_hw_update (struct rp1_vec * vec , dma_addr_t addr , u32 offset , u32 stride )
527562{
563+ unsigned long flags ;
564+
565+ spin_lock_irqsave (& vec -> hw_lock , flags );
566+
528567 /*
529568 * Update STRIDE, DMAH and DMAL only. When called after rp1vec_hw_setup(),
530569 * DMA starts immediately; if already running, the buffer will flip at
531- * the next vertical sync event.
570+ * the next vertical sync event. In interlaced mode, we need to adjust
571+ * the address and stride to display only the current field, saving
572+ * the original address (so it can be flipped for subsequent fields).
532573 */
533- u64 a = addr + offset ;
534-
535- if (vec -> fake_31khz ) {
536- a += stride ;
574+ addr += offset ;
575+ vec -> last_dma_addr = addr ;
576+ vec -> last_stride = stride ;
577+ if (vec -> fake_31khz || vec -> interlaced ) {
578+ if (vec -> fake_31khz || vec -> lower_field_flag )
579+ addr += stride ;
537580 stride *= 2 ;
538581 }
539582 VEC_WRITE (VEC_DMA_STRIDE , stride );
540- VEC_WRITE (VEC_DMA_ADDR_H , a >> 32 );
541- VEC_WRITE (VEC_DMA_ADDR_L , a & 0xFFFFFFFFu );
583+ VEC_WRITE (VEC_DMA_ADDR_H , addr >> 32 );
584+ VEC_WRITE (VEC_DMA_ADDR_L , addr & 0xFFFFFFFFu );
585+
586+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
542587}
543588
544589void rp1vec_hw_stop (struct rp1_vec * vec )
545590{
591+ unsigned long flags ;
592+
546593 /*
547594 * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for
548595 * the current and any queued frame to end. "Force drain" flags are not used,
549596 * as they seem to prevent DMA from re-starting properly; it's safer to wait.
550597 */
551598
599+ spin_lock_irqsave (& vec -> hw_lock , flags );
600+ vec -> last_dma_addr = 0 ;
552601 reinit_completion (& vec -> finished );
553602 VEC_WRITE (VEC_CONTROL , 0 );
603+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
604+
554605 if (!wait_for_completion_timeout (& vec -> finished , HZ / 10 ))
555606 drm_err (& vec -> drm , "%s: timed out waiting for idle\n" , __func__ );
556607 VEC_WRITE (VEC_IRQ_ENABLES , 0 );
@@ -561,7 +612,10 @@ void rp1vec_hw_vblank_ctrl(struct rp1_vec *vec, int enable)
561612 VEC_WRITE (VEC_IRQ_ENABLES ,
562613 BITS (VEC_IRQ_ENABLES_DONE , 1 ) |
563614 BITS (VEC_IRQ_ENABLES_DMA , (enable ? 1 : 0 )) |
564- BITS (VEC_IRQ_ENABLES_MATCH_ROW , 1023 ));
615+ #ifdef FIELD_WOBBLE
616+ BITS (VEC_IRQ_ENABLES_MATCH , vec -> interlaced ) |
617+ #endif
618+ BITS (VEC_IRQ_ENABLES_MATCH_ROW , 32 ));
565619}
566620
567621irqreturn_t rp1vec_hw_isr (int irq , void * dev )
@@ -575,6 +629,31 @@ irqreturn_t rp1vec_hw_isr(int irq, void *dev)
575629 drm_crtc_handle_vblank (& vec -> pipe .crtc );
576630 if (u & VEC_IRQ_FLAGS_DONE_BITS )
577631 complete (& vec -> finished );
632+
633+ #ifdef FIELD_WOBBLE
634+ /*
635+ * VEC has native support for interlaced modes, but that only
636+ * supports buffer-flips per frame (30fps), not field (60fps).
637+ * Instead, we always run the VEC front end in a "progressive"
638+ * mode and use the "field-wobble" trick (see RP1 DPI driver).
639+ */
640+ if ((u & VEC_IRQ_FLAGS_MATCH_BITS ) && vec -> interlaced ) {
641+ unsigned long flags ;
642+ dma_addr_t a ;
643+
644+ spin_lock_irqsave (& vec -> hw_lock , flags );
645+ vec -> lower_field_flag = !vec -> lower_field_flag ;
646+ a = vec -> last_dma_addr ;
647+ if (a ) {
648+ if (vec -> lower_field_flag )
649+ a += vec -> last_stride ;
650+ VEC_WRITE (VEC_DMA_ADDR_H , a >> 32 );
651+ VEC_WRITE (VEC_DMA_ADDR_L , a & 0xFFFFFFFFu );
652+ }
653+ spin_unlock_irqrestore (& vec -> hw_lock , flags );
654+ }
655+ #endif
578656 }
657+
579658 return u ? IRQ_HANDLED : IRQ_NONE ;
580659}
0 commit comments