Skip to content

Commit 008095e

Browse files
Boris BrezillonBoris Brezillon
authored andcommitted
drm/vc4: Add support for the transposer block
The transposer block is providing support for mem-to-mem composition, which is exposed as a drm_writeback connector in DRM. Add a driver to support this feature. Signed-off-by: Boris Brezillon <[email protected]> Reviewed-by: Eric Anholt <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 1ebe99a commit 008095e

File tree

7 files changed

+607
-24
lines changed

7 files changed

+607
-24
lines changed

Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ Required properties for DSI:
7474
The 3 clocks output from the DSI analog PHY: dsi[01]_byte,
7575
dsi[01]_ddr2, and dsi[01]_ddr
7676

77+
Required properties for the TXP (writeback) block:
78+
- compatible: Should be "brcm,bcm2835-txp"
79+
- reg: Physical base address and length of the TXP block's registers
80+
- interrupts: The interrupt number
81+
See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
82+
7783
[1] Documentation/devicetree/bindings/media/video-interfaces.txt
7884

7985
Example:

drivers/gpu/drm/vc4/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ vc4-y := \
1919
vc4_plane.o \
2020
vc4_render_cl.o \
2121
vc4_trace_points.o \
22+
vc4_txp.o \
2223
vc4_v3d.o \
2324
vc4_validate.o \
2425
vc4_validate_shaders.o

drivers/gpu/drm/vc4/vc4_crtc.c

Lines changed: 114 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ struct vc4_crtc_state {
4646
struct drm_crtc_state base;
4747
/* Dlist area for this CRTC configuration. */
4848
struct drm_mm_node mm;
49+
bool feed_txp;
50+
bool txp_armed;
4951
};
5052

5153
static inline struct vc4_crtc_state *
@@ -324,10 +326,8 @@ static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc)
324326
return NULL;
325327
}
326328

327-
static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
329+
static void vc4_crtc_config_pv(struct drm_crtc *crtc)
328330
{
329-
struct drm_device *dev = crtc->dev;
330-
struct vc4_dev *vc4 = to_vc4_dev(dev);
331331
struct drm_encoder *encoder = vc4_get_crtc_encoder(crtc);
332332
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
333333
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
@@ -338,12 +338,6 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
338338
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
339339
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
340340
u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
341-
bool debug_dump_regs = false;
342-
343-
if (debug_dump_regs) {
344-
DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc));
345-
vc4_crtc_dump_regs(vc4_crtc);
346-
}
347341

348342
/* Reset the PV fifo. */
349343
CRTC_WRITE(PV_CONTROL, 0);
@@ -419,6 +413,49 @@ static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
419413
PV_CONTROL_CLK_SELECT) |
420414
PV_CONTROL_FIFO_CLR |
421415
PV_CONTROL_EN);
416+
}
417+
418+
static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
419+
{
420+
struct drm_device *dev = crtc->dev;
421+
struct vc4_dev *vc4 = to_vc4_dev(dev);
422+
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
423+
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
424+
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
425+
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
426+
bool debug_dump_regs = false;
427+
428+
if (debug_dump_regs) {
429+
DRM_INFO("CRTC %d regs before:\n", drm_crtc_index(crtc));
430+
vc4_crtc_dump_regs(vc4_crtc);
431+
}
432+
433+
if (vc4_crtc->channel == 2) {
434+
u32 dispctrl;
435+
u32 dsp3_mux;
436+
437+
/*
438+
* SCALER_DISPCTRL_DSP3 = X, where X < 2 means 'connect DSP3 to
439+
* FIFO X'.
440+
* SCALER_DISPCTRL_DSP3 = 3 means 'disable DSP 3'.
441+
*
442+
* DSP3 is connected to FIFO2 unless the transposer is
443+
* enabled. In this case, FIFO 2 is directly accessed by the
444+
* TXP IP, and we need to disable the FIFO2 -> pixelvalve1
445+
* route.
446+
*/
447+
if (vc4_state->feed_txp)
448+
dsp3_mux = VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX);
449+
else
450+
dsp3_mux = VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
451+
452+
dispctrl = HVS_READ(SCALER_DISPCTRL) &
453+
~SCALER_DISPCTRL_DSP3_MUX_MASK;
454+
HVS_WRITE(SCALER_DISPCTRL, dispctrl | dsp3_mux);
455+
}
456+
457+
if (!vc4_state->feed_txp)
458+
vc4_crtc_config_pv(crtc);
422459

423460
HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
424461
SCALER_DISPBKGND_AUTOHS |
@@ -499,6 +536,13 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
499536
}
500537
}
501538

539+
void vc4_crtc_txp_armed(struct drm_crtc_state *state)
540+
{
541+
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
542+
543+
vc4_state->txp_armed = true;
544+
}
545+
502546
static void vc4_crtc_update_dlist(struct drm_crtc *crtc)
503547
{
504548
struct drm_device *dev = crtc->dev;
@@ -514,8 +558,11 @@ static void vc4_crtc_update_dlist(struct drm_crtc *crtc)
514558
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
515559

516560
spin_lock_irqsave(&dev->event_lock, flags);
517-
vc4_crtc->event = crtc->state->event;
518-
crtc->state->event = NULL;
561+
562+
if (!vc4_state->feed_txp || vc4_state->txp_armed) {
563+
vc4_crtc->event = crtc->state->event;
564+
crtc->state->event = NULL;
565+
}
519566

520567
HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
521568
vc4_state->mm.start);
@@ -533,8 +580,8 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
533580
struct drm_device *dev = crtc->dev;
534581
struct vc4_dev *vc4 = to_vc4_dev(dev);
535582
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
536-
struct drm_crtc_state *state = crtc->state;
537-
struct drm_display_mode *mode = &state->adjusted_mode;
583+
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
584+
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
538585

539586
require_hvs_enabled(dev);
540587

@@ -546,15 +593,21 @@ static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
546593

547594
/* Turn on the scaler, which will wait for vstart to start
548595
* compositing.
596+
* When feeding the transposer, we should operate in oneshot
597+
* mode.
549598
*/
550599
HVS_WRITE(SCALER_DISPCTRLX(vc4_crtc->channel),
551600
VC4_SET_FIELD(mode->hdisplay, SCALER_DISPCTRLX_WIDTH) |
552601
VC4_SET_FIELD(mode->vdisplay, SCALER_DISPCTRLX_HEIGHT) |
553-
SCALER_DISPCTRLX_ENABLE);
602+
SCALER_DISPCTRLX_ENABLE |
603+
(vc4_state->feed_txp ? SCALER_DISPCTRLX_ONESHOT : 0));
554604

555-
/* Turn on the pixel valve, which will emit the vstart signal. */
556-
CRTC_WRITE(PV_V_CONTROL,
557-
CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
605+
/* When feeding the transposer block the pixelvalve is unneeded and
606+
* should not be enabled.
607+
*/
608+
if (!vc4_state->feed_txp)
609+
CRTC_WRITE(PV_V_CONTROL,
610+
CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
558611
}
559612

560613
static enum drm_mode_status vc4_crtc_mode_valid(struct drm_crtc *crtc,
@@ -579,8 +632,10 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
579632
struct drm_plane *plane;
580633
unsigned long flags;
581634
const struct drm_plane_state *plane_state;
635+
struct drm_connector *conn;
636+
struct drm_connector_state *conn_state;
582637
u32 dlist_count = 0;
583-
int ret;
638+
int ret, i;
584639

585640
/* The pixelvalve can only feed one encoder (and encoders are
586641
* 1:1 with connectors.)
@@ -600,6 +655,24 @@ static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
600655
if (ret)
601656
return ret;
602657

658+
for_each_new_connector_in_state(state->state, conn, conn_state, i) {
659+
if (conn_state->crtc != crtc)
660+
continue;
661+
662+
/* The writeback connector is implemented using the transposer
663+
* block which is directly taking its data from the HVS FIFO.
664+
*/
665+
if (conn->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) {
666+
state->no_vblank = true;
667+
vc4_state->feed_txp = true;
668+
} else {
669+
state->no_vblank = false;
670+
vc4_state->feed_txp = false;
671+
}
672+
673+
break;
674+
}
675+
603676
return 0;
604677
}
605678

@@ -713,25 +786,31 @@ static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
713786

714787
spin_lock_irqsave(&dev->event_lock, flags);
715788
if (vc4_crtc->event &&
716-
(vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)))) {
789+
(vc4_state->mm.start == HVS_READ(SCALER_DISPLACTX(chan)) ||
790+
vc4_state->feed_txp)) {
717791
drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
718792
vc4_crtc->event = NULL;
719793
drm_crtc_vblank_put(crtc);
720794
}
721795
spin_unlock_irqrestore(&dev->event_lock, flags);
722796
}
723797

798+
void vc4_crtc_handle_vblank(struct vc4_crtc *crtc)
799+
{
800+
crtc->t_vblank = ktime_get();
801+
drm_crtc_handle_vblank(&crtc->base);
802+
vc4_crtc_handle_page_flip(crtc);
803+
}
804+
724805
static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
725806
{
726807
struct vc4_crtc *vc4_crtc = data;
727808
u32 stat = CRTC_READ(PV_INTSTAT);
728809
irqreturn_t ret = IRQ_NONE;
729810

730811
if (stat & PV_INT_VFP_START) {
731-
vc4_crtc->t_vblank = ktime_get();
732812
CRTC_WRITE(PV_INTSTAT, PV_INT_VFP_START);
733-
drm_crtc_handle_vblank(&vc4_crtc->base);
734-
vc4_crtc_handle_page_flip(vc4_crtc);
813+
vc4_crtc_handle_vblank(vc4_crtc);
735814
ret = IRQ_HANDLED;
736815
}
737816

@@ -884,12 +963,15 @@ static int vc4_page_flip(struct drm_crtc *crtc,
884963

885964
static struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
886965
{
887-
struct vc4_crtc_state *vc4_state;
966+
struct vc4_crtc_state *vc4_state, *old_vc4_state;
888967

889968
vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
890969
if (!vc4_state)
891970
return NULL;
892971

972+
old_vc4_state = to_vc4_crtc_state(crtc->state);
973+
vc4_state->feed_txp = old_vc4_state->feed_txp;
974+
893975
__drm_atomic_helper_crtc_duplicate_state(crtc, &vc4_state->base);
894976
return &vc4_state->base;
895977
}
@@ -987,9 +1069,17 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
9871069
struct drm_encoder *encoder;
9881070

9891071
drm_for_each_encoder(encoder, drm) {
990-
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
1072+
struct vc4_encoder *vc4_encoder;
9911073
int i;
9921074

1075+
/* HVS FIFO2 can feed the TXP IP. */
1076+
if (crtc_data->hvs_channel == 2 &&
1077+
encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) {
1078+
encoder->possible_crtcs |= drm_crtc_mask(crtc);
1079+
continue;
1080+
}
1081+
1082+
vc4_encoder = to_vc4_encoder(encoder);
9931083
for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) {
9941084
if (vc4_encoder->type == encoder_types[i]) {
9951085
vc4_encoder->clock_select = i;

drivers/gpu/drm/vc4/vc4_debugfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static const struct drm_info_list vc4_debugfs_list[] = {
2121
{"dsi1_regs", vc4_dsi_debugfs_regs, 0, (void *)(uintptr_t)1},
2222
{"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
2323
{"vec_regs", vc4_vec_debugfs_regs, 0},
24+
{"txp_regs", vc4_txp_debugfs_regs, 0},
2425
{"hvs_regs", vc4_hvs_debugfs_regs, 0},
2526
{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
2627
{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},

drivers/gpu/drm/vc4/vc4_drv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ static struct platform_driver *const component_drivers[] = {
344344
&vc4_vec_driver,
345345
&vc4_dpi_driver,
346346
&vc4_dsi_driver,
347+
&vc4_txp_driver,
347348
&vc4_hvs_driver,
348349
&vc4_crtc_driver,
349350
&vc4_v3d_driver,

drivers/gpu/drm/vc4/vc4_drv.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ struct vc4_dev {
7373
struct vc4_dpi *dpi;
7474
struct vc4_dsi *dsi1;
7575
struct vc4_vec *vec;
76+
struct vc4_txp *txp;
7677

7778
struct vc4_hang_state *hang_state;
7879

@@ -698,6 +699,8 @@ bool vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
698699
bool in_vblank_irq, int *vpos, int *hpos,
699700
ktime_t *stime, ktime_t *etime,
700701
const struct drm_display_mode *mode);
702+
void vc4_crtc_handle_vblank(struct vc4_crtc *crtc);
703+
void vc4_crtc_txp_armed(struct drm_crtc_state *state);
701704

702705
/* vc4_debugfs.c */
703706
int vc4_debugfs_init(struct drm_minor *minor);
@@ -745,6 +748,10 @@ int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
745748
extern struct platform_driver vc4_vec_driver;
746749
int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
747750

751+
/* vc4_txp.c */
752+
extern struct platform_driver vc4_txp_driver;
753+
int vc4_txp_debugfs_regs(struct seq_file *m, void *unused);
754+
748755
/* vc4_irq.c */
749756
irqreturn_t vc4_irq(int irq, void *arg);
750757
void vc4_irq_preinstall(struct drm_device *dev);

0 commit comments

Comments
 (0)