@@ -354,42 +354,26 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
354
354
u32 in_format , u32 bus_format , bool de_inv ,
355
355
struct drm_display_mode const * mode )
356
356
{
357
- u32 shift , imask , omask , rgbsz ;
357
+ u32 shift , imask , omask , rgbsz , vctrl ;
358
358
int i ;
359
359
360
- pr_info ("%s: in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d %dkHz %cH%cV%cD%cC" ,
361
- __func__ , in_format , in_format >> 8 , in_format >> 16 , in_format >> 24 , bus_format ,
362
- mode -> hdisplay , mode -> vdisplay ,
363
- mode -> htotal , mode -> vtotal ,
364
- mode -> clock ,
365
- (mode -> flags & DRM_MODE_FLAG_NHSYNC ) ? '-' : '+' ,
366
- (mode -> flags & DRM_MODE_FLAG_NVSYNC ) ? '-' : '+' ,
367
- de_inv ? '-' : '+' ,
368
- dpi -> clk_inv ? '-' : '+' );
360
+ drm_info (& dpi -> drm ,
361
+ "in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d%s %dkHz %cH%cV%cD%cC" ,
362
+ in_format , in_format >> 8 , in_format >> 16 , in_format >> 24 , bus_format ,
363
+ mode -> hdisplay , mode -> vdisplay ,
364
+ mode -> htotal , mode -> vtotal ,
365
+ (mode -> flags & DRM_MODE_FLAG_INTERLACE ) ? "i" : "" ,
366
+ mode -> clock ,
367
+ (mode -> flags & DRM_MODE_FLAG_NHSYNC ) ? '-' : '+' ,
368
+ (mode -> flags & DRM_MODE_FLAG_NVSYNC ) ? '-' : '+' ,
369
+ de_inv ? '-' : '+' ,
370
+ dpi -> clk_inv ? '-' : '+' );
369
371
370
372
/*
371
373
* Configure all DPI/DMA block registers, except base address.
372
374
* DMA will not actually start until a FB base address is specified
373
375
* using rp1dpi_hw_update().
374
376
*/
375
- rp1dpi_hw_write (dpi , DPI_DMA_VISIBLE_AREA ,
376
- BITS (DPI_DMA_VISIBLE_AREA_ROWSM1 , mode -> vdisplay - 1 ) |
377
- BITS (DPI_DMA_VISIBLE_AREA_COLSM1 , mode -> hdisplay - 1 ));
378
-
379
- rp1dpi_hw_write (dpi , DPI_DMA_SYNC_WIDTH ,
380
- BITS (DPI_DMA_SYNC_WIDTH_ROWSM1 , mode -> vsync_end - mode -> vsync_start - 1 ) |
381
- BITS (DPI_DMA_SYNC_WIDTH_COLSM1 , mode -> hsync_end - mode -> hsync_start - 1 ));
382
-
383
- /* In these registers, "back porch" time includes sync width */
384
- rp1dpi_hw_write (dpi , DPI_DMA_BACK_PORCH ,
385
- BITS (DPI_DMA_BACK_PORCH_ROWSM1 , mode -> vtotal - mode -> vsync_start - 1 ) |
386
- BITS (DPI_DMA_BACK_PORCH_COLSM1 , mode -> htotal - mode -> hsync_start - 1 ));
387
-
388
- rp1dpi_hw_write (dpi , DPI_DMA_FRONT_PORCH ,
389
- BITS (DPI_DMA_FRONT_PORCH_ROWSM1 , mode -> vsync_start - mode -> vdisplay - 1 ) |
390
- BITS (DPI_DMA_FRONT_PORCH_COLSM1 , mode -> hsync_start - mode -> hdisplay - 1 ));
391
-
392
- /* Input to output pixel format conversion */
393
377
for (i = 0 ; i < ARRAY_SIZE (my_formats ); ++ i ) {
394
378
if (my_formats [i ].format == in_format )
395
379
break ;
@@ -417,6 +401,80 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
417
401
BITS (DPI_DMA_QOS_LLEV , 0x8 ) |
418
402
BITS (DPI_DMA_QOS_LQOS , 0x7 ));
419
403
404
+ if (!(mode -> flags & DRM_MODE_FLAG_INTERLACE )) {
405
+ rp1dpi_hw_write (dpi , DPI_DMA_VISIBLE_AREA ,
406
+ BITS (DPI_DMA_VISIBLE_AREA_ROWSM1 , mode -> vdisplay - 1 ) |
407
+ BITS (DPI_DMA_VISIBLE_AREA_COLSM1 , mode -> hdisplay - 1 ));
408
+
409
+ rp1dpi_hw_write (dpi , DPI_DMA_SYNC_WIDTH ,
410
+ BITS (DPI_DMA_SYNC_WIDTH_ROWSM1 , mode -> vsync_end - mode -> vsync_start - 1 ) |
411
+ BITS (DPI_DMA_SYNC_WIDTH_COLSM1 , mode -> hsync_end - mode -> hsync_start - 1 ));
412
+
413
+ /* In these registers, "back porch" time includes sync width */
414
+ rp1dpi_hw_write (dpi , DPI_DMA_BACK_PORCH ,
415
+ BITS (DPI_DMA_BACK_PORCH_ROWSM1 , mode -> vtotal - mode -> vsync_start - 1 ) |
416
+ BITS (DPI_DMA_BACK_PORCH_COLSM1 , mode -> htotal - mode -> hsync_start - 1 ));
417
+
418
+ rp1dpi_hw_write (dpi , DPI_DMA_FRONT_PORCH ,
419
+ BITS (DPI_DMA_FRONT_PORCH_ROWSM1 , mode -> vsync_start - mode -> vdisplay - 1 ) |
420
+ BITS (DPI_DMA_FRONT_PORCH_COLSM1 , mode -> hsync_start - mode -> hdisplay - 1 ));
421
+
422
+ vctrl = BITS (DPI_DMA_CONTROL_VSYNC_POL , !!(mode -> flags & DRM_MODE_FLAG_NVSYNC )) |
423
+ BITS (DPI_DMA_CONTROL_VBP_EN , (mode -> vtotal != mode -> vsync_start )) |
424
+ BITS (DPI_DMA_CONTROL_VFP_EN , (mode -> vsync_start != mode -> vdisplay )) |
425
+ BITS (DPI_DMA_CONTROL_VSYNC_EN , (mode -> vsync_end != mode -> vsync_start ));
426
+
427
+ dpi -> interlaced = false;
428
+ } else {
429
+ /*
430
+ * Experimental interlace support
431
+ *
432
+ * RP1 DPI hardware wasn't designed to support interlace, but lets us change
433
+ * both the VFP line count and the next DMA address while running. That allows
434
+ * pixel data to be correctly timed for interlace, but VSYNC remains wrong.
435
+ *
436
+ * It is necessary to use external hardware (such as PIO) to regenerate VSYNC
437
+ * based on HSYNC, DE (which *must* both be mapped to GPIOs 1, 3 respectively).
438
+ * This driver includes a PIO program to do that, when DE is enabled.
439
+ *
440
+ * An alternative fixup is to synthesize CSYNC from HSYNC and modified-VSYNC.
441
+ * We don't implement that here, but to facilitate it, DPI's VSYNC is replaced
442
+ * by a "helper signal" that pulses low for 1 or 2 scan-lines, starting 2.5 or
443
+ * 3.0 scan-lines before the vertical datum "0v".
444
+ */
445
+ int vact = mode -> vdisplay >> 1 ; /* visible lines per field. Can't do half-lines */
446
+ int vtot0 = mode -> vtotal >> 1 ; /* vtotal should always be odd when interlaced. */
447
+ int vfp0 = (mode -> vsync_start >= mode -> vdisplay + 7 ) ?
448
+ ((mode -> vsync_start - mode -> vdisplay - 5 ) >> 1 ) : 1 ;
449
+ int vbp = max (0 , vtot0 - vact - vfp0 );
450
+
451
+ rp1dpi_hw_write (dpi , DPI_DMA_VISIBLE_AREA ,
452
+ BITS (DPI_DMA_VISIBLE_AREA_ROWSM1 , vact - 1 ) |
453
+ BITS (DPI_DMA_VISIBLE_AREA_COLSM1 , mode -> hdisplay - 1 ));
454
+
455
+ rp1dpi_hw_write (dpi , DPI_DMA_SYNC_WIDTH ,
456
+ BITS (DPI_DMA_SYNC_WIDTH_ROWSM1 , vtot0 - 2 ) |
457
+ BITS (DPI_DMA_SYNC_WIDTH_COLSM1 , mode -> hsync_end - mode -> hsync_start - 1 ));
458
+
459
+ rp1dpi_hw_write (dpi , DPI_DMA_BACK_PORCH ,
460
+ BITS (DPI_DMA_BACK_PORCH_ROWSM1 , vbp - 1 ) |
461
+ BITS (DPI_DMA_BACK_PORCH_COLSM1 , mode -> htotal - mode -> hsync_start - 1 ));
462
+
463
+ dpi -> shorter_front_porch =
464
+ BITS (DPI_DMA_FRONT_PORCH_ROWSM1 , vfp0 - 1 ) |
465
+ BITS (DPI_DMA_FRONT_PORCH_COLSM1 , mode -> hsync_start - mode -> hdisplay - 1 );
466
+ rp1dpi_hw_write (dpi , DPI_DMA_FRONT_PORCH , dpi -> shorter_front_porch );
467
+
468
+ vctrl = BITS (DPI_DMA_CONTROL_VSYNC_POL , 0 ) |
469
+ BITS (DPI_DMA_CONTROL_VBP_EN , (vbp > 0 )) |
470
+ BITS (DPI_DMA_CONTROL_VFP_EN , 1 ) |
471
+ BITS (DPI_DMA_CONTROL_VSYNC_EN , 1 );
472
+
473
+ dpi -> interlaced = true;
474
+ }
475
+ dpi -> lower_field_flag = false;
476
+ dpi -> last_dma_addr = 0 ;
477
+
420
478
rp1dpi_hw_write (dpi , DPI_DMA_IRQ_FLAGS , -1 );
421
479
rp1dpi_hw_vblank_ctrl (dpi , 1 );
422
480
@@ -425,49 +483,64 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi,
425
483
pr_warn ("%s: Unexpectedly busy at start!" , __func__ );
426
484
427
485
rp1dpi_hw_write (dpi , DPI_DMA_CONTROL ,
486
+ vctrl |
428
487
BITS (DPI_DMA_CONTROL_ARM , !i ) |
429
488
BITS (DPI_DMA_CONTROL_AUTO_REPEAT , 1 ) |
430
489
BITS (DPI_DMA_CONTROL_HIGH_WATER , 448 ) |
431
490
BITS (DPI_DMA_CONTROL_DEN_POL , de_inv ) |
432
491
BITS (DPI_DMA_CONTROL_HSYNC_POL , !!(mode -> flags & DRM_MODE_FLAG_NHSYNC )) |
433
- BITS (DPI_DMA_CONTROL_VSYNC_POL , !!(mode -> flags & DRM_MODE_FLAG_NVSYNC )) |
434
- BITS (DPI_DMA_CONTROL_COLORM , 0 ) |
435
- BITS (DPI_DMA_CONTROL_SHUTDN , 0 ) |
436
492
BITS (DPI_DMA_CONTROL_HBP_EN , (mode -> htotal != mode -> hsync_end )) |
437
493
BITS (DPI_DMA_CONTROL_HFP_EN , (mode -> hsync_start != mode -> hdisplay )) |
438
- BITS (DPI_DMA_CONTROL_VBP_EN , (mode -> vtotal != mode -> vsync_end )) |
439
- BITS (DPI_DMA_CONTROL_VFP_EN , (mode -> vsync_start != mode -> vdisplay )) |
440
- BITS (DPI_DMA_CONTROL_HSYNC_EN , (mode -> hsync_end != mode -> hsync_start )) |
441
- BITS (DPI_DMA_CONTROL_VSYNC_EN , (mode -> vsync_end != mode -> vsync_start )));
494
+ BITS (DPI_DMA_CONTROL_HSYNC_EN , (mode -> hsync_end != mode -> hsync_start )));
442
495
}
443
496
444
497
void rp1dpi_hw_update (struct rp1_dpi * dpi , dma_addr_t addr , u32 offset , u32 stride )
445
498
{
446
- u64 a = addr + offset ;
499
+ unsigned long flags ;
500
+
501
+ spin_lock_irqsave (& dpi -> hw_lock , flags );
447
502
448
503
/*
449
504
* Update STRIDE, DMAH and DMAL only. When called after rp1dpi_hw_setup(),
450
505
* DMA starts immediately; if already running, the buffer will flip at
451
- * the next vertical sync event.
506
+ * the next vertical sync event. In interlaced mode, we need to adjust
507
+ * the address and stride to display only the current field, saving
508
+ * the original address (so it can be flipped for subsequent fields).
452
509
*/
510
+ addr += offset ;
511
+ dpi -> last_dma_addr = addr ;
512
+ dpi -> last_stride = stride ;
513
+ if (dpi -> interlaced ) {
514
+ if (dpi -> lower_field_flag )
515
+ addr += stride ;
516
+ stride *= 2 ;
517
+ }
453
518
rp1dpi_hw_write (dpi , DPI_DMA_DMA_STRIDE , stride );
454
- rp1dpi_hw_write (dpi , DPI_DMA_DMA_ADDR_H , a >> 32 );
455
- rp1dpi_hw_write (dpi , DPI_DMA_DMA_ADDR_L , a & 0xFFFFFFFFu );
519
+ rp1dpi_hw_write (dpi , DPI_DMA_DMA_ADDR_H , addr >> 32 );
520
+ rp1dpi_hw_write (dpi , DPI_DMA_DMA_ADDR_L , addr & 0xFFFFFFFFu );
521
+
522
+ spin_unlock_irqrestore (& dpi -> hw_lock , flags );
456
523
}
457
524
458
525
void rp1dpi_hw_stop (struct rp1_dpi * dpi )
459
526
{
460
527
u32 ctrl ;
528
+ unsigned long flags ;
461
529
462
530
/*
463
- * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for
464
- * the current and any queued frame to end. "Force drain" flags are not used,
465
- * as they seem to prevent DMA from re-starting properly; it's safer to wait.
531
+ * Stop DMA by turning off Auto-Repeat (and disable S/W field-flip),
532
+ * then wait up to 100ms for the current and any queued frame to end.
533
+ * (There is a "force drain" flag, but it can leave DPI in a broken
534
+ * state which prevents it from restarting; it's safer to wait.)
466
535
*/
536
+ spin_lock_irqsave (& dpi -> hw_lock , flags );
537
+ dpi -> last_dma_addr = 0 ;
467
538
reinit_completion (& dpi -> finished );
468
539
ctrl = rp1dpi_hw_read (dpi , DPI_DMA_CONTROL );
469
540
ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK );
470
541
rp1dpi_hw_write (dpi , DPI_DMA_CONTROL , ctrl );
542
+ spin_unlock_irqrestore (& dpi -> hw_lock , flags );
543
+
471
544
if (!wait_for_completion_timeout (& dpi -> finished , HZ / 10 ))
472
545
drm_err (& dpi -> drm , "%s: timed out waiting for idle\n" , __func__ );
473
546
rp1dpi_hw_write (dpi , DPI_DMA_IRQ_EN , 0 );
@@ -476,10 +549,11 @@ void rp1dpi_hw_stop(struct rp1_dpi *dpi)
476
549
void rp1dpi_hw_vblank_ctrl (struct rp1_dpi * dpi , int enable )
477
550
{
478
551
rp1dpi_hw_write (dpi , DPI_DMA_IRQ_EN ,
479
- BITS (DPI_DMA_IRQ_EN_AFIFO_EMPTY , 1 ) |
480
- BITS (DPI_DMA_IRQ_EN_UNDERFLOW , 1 ) |
481
- BITS (DPI_DMA_IRQ_EN_DMA_READY , !!enable ) |
482
- BITS (DPI_DMA_IRQ_EN_MATCH_LINE , 4095 ));
552
+ BITS (DPI_DMA_IRQ_EN_AFIFO_EMPTY , 1 ) |
553
+ BITS (DPI_DMA_IRQ_EN_UNDERFLOW , 1 ) |
554
+ BITS (DPI_DMA_IRQ_EN_DMA_READY , !!enable ) |
555
+ BITS (DPI_DMA_IRQ_EN_MATCH , dpi -> interlaced ) |
556
+ BITS (DPI_DMA_IRQ_EN_MATCH_LINE , 32 ));
483
557
}
484
558
485
559
irqreturn_t rp1dpi_hw_isr (int irq , void * dev )
@@ -498,7 +572,34 @@ irqreturn_t rp1dpi_hw_isr(int irq, void *dev)
498
572
drm_crtc_handle_vblank (& dpi -> pipe .crtc );
499
573
if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK )
500
574
complete (& dpi -> finished );
575
+
576
+ /*
577
+ * Added for interlace support: We use this mid-frame interrupt to
578
+ * wobble the VFP between fields, re-submitting the next-buffer address
579
+ * with an offset to display the opposite field. NB: rp1dpi_hw_update()
580
+ * may be called at any time, before or after, so locking is needed.
581
+ * H/W Auto-update is no longer needed (unless this IRQ is lost).
582
+ */
583
+ if ((u & DPI_DMA_IRQ_FLAGS_MATCH_MASK ) && dpi -> interlaced ) {
584
+ unsigned long flags ;
585
+ dma_addr_t a ;
586
+
587
+ spin_lock_irqsave (& dpi -> hw_lock , flags );
588
+ dpi -> lower_field_flag = !dpi -> lower_field_flag ;
589
+ rp1dpi_hw_write (dpi , DPI_DMA_FRONT_PORCH ,
590
+ dpi -> shorter_front_porch +
591
+ BITS (DPI_DMA_FRONT_PORCH_ROWSM1 , dpi -> lower_field_flag ));
592
+ a = dpi -> last_dma_addr ;
593
+ if (a ) {
594
+ if (dpi -> lower_field_flag )
595
+ a += dpi -> last_stride ;
596
+ rp1dpi_hw_write (dpi , DPI_DMA_DMA_ADDR_H , a >> 32 );
597
+ rp1dpi_hw_write (dpi , DPI_DMA_DMA_ADDR_L , a & 0xFFFFFFFFu );
598
+ }
599
+ spin_unlock_irqrestore (& dpi -> hw_lock , flags );
600
+ }
501
601
}
502
602
}
603
+
503
604
return u ? IRQ_HANDLED : IRQ_NONE ;
504
605
}
0 commit comments