From f6517c74af2065245698c5f5c06281f413440be0 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 11 Jan 2022 11:41:12 +0000 Subject: [PATCH 1/2] drm/vc4: Fix interrupt masking for HVS5. The bits in both DISPCTRL and DISPSTAT have moved between hvs4 and hvs5, and the driver wasn't taking that into account. This lead to VSTART being enabled on channel 2, which nothing then acknowledged and lead to the parent interrupt being disabled. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_hvs.c | 71 ++++++++++++++++++++++++---------- drivers/gpu/drm/vc4/vc4_regs.h | 21 ++++++++++ 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index f743a5ad6b61f7..45533e85d059fc 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -621,7 +621,8 @@ static void vc4_hvs_install_dlist(struct vc4_dev *vc4, unsigned int channel) hvs->fifo[channel].pending = false; reg = HVS_READ(SCALER_DISPCTRL); - reg &= ~BIT(7 + (channel * (vc4->hvs->hvs5 ? 4 : 2))); + reg &= ~(vc4->hvs->hvs5 ? SCALER5_DISPCTRL_DSPEIEOF(channel) : + SCALER_DISPCTRL_DSPEIEOF(channel)); HVS_WRITE(SCALER_DISPCTRL, reg); spin_unlock_irqrestore(&hvs->hw_dlist_lock, flags); @@ -641,7 +642,9 @@ static void vc4_hvs_schedule_dlist_update(struct vc4_dev *vc4, } HVS_WRITE(SCALER_DISPCTRL, - HVS_READ(SCALER_DISPCTRL) | BIT(7 + (channel * (vc4->hvs->hvs5 ? 4 : 2)))); + HVS_READ(SCALER_DISPCTRL) | + (vc4->hvs->hvs5 ? SCALER5_DISPCTRL_DSPEIEOF(channel) : + SCALER_DISPCTRL_DSPEIEOF(channel))); hvs->fifo[channel].pending = true; @@ -827,7 +830,8 @@ void vc4_hvs_mask_underrun(struct drm_device *dev, int channel) struct vc4_dev *vc4 = to_vc4_dev(dev); u32 dispctrl = HVS_READ(SCALER_DISPCTRL); - dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel); + dispctrl &= ~(vc4->hvs->hvs5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : + SCALER_DISPCTRL_DSPEISLUR(channel)); HVS_WRITE(SCALER_DISPCTRL, dispctrl); } @@ -837,7 +841,8 @@ void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel) struct vc4_dev *vc4 = to_vc4_dev(dev); u32 dispctrl = HVS_READ(SCALER_DISPCTRL); - dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel); + dispctrl |= vc4->hvs->hvs5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : + SCALER_DISPCTRL_DSPEISLUR(channel); HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_EUFLOW(channel)); @@ -867,7 +872,8 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) { /* Interrupt masking is not always honored, so check it here. */ if (status & SCALER_DISPSTAT_EUFLOW(channel) && - control & SCALER_DISPCTRL_DSPEISLUR(channel)) { + control & (vc4->hvs->hvs5 ? SCALER5_DISPCTRL_DSPEISLUR(channel) : + SCALER_DISPCTRL_DSPEISLUR(channel))) { vc4_hvs_mask_underrun(dev, channel); vc4_hvs_report_underrun(dev); @@ -881,9 +887,14 @@ static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) } /* Clear every per-channel interrupt flag. */ - HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | - SCALER_DISPSTAT_IRQMASK(1) | - SCALER_DISPSTAT_IRQMASK(2)); + if (vc4->hvs->hvs5) + HVS_WRITE(SCALER_DISPSTAT, SCALER5_DISPSTAT_IRQMASK(0) | + SCALER5_DISPSTAT_IRQMASK(1) | + SCALER5_DISPSTAT_IRQMASK(2)); + else + HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | + SCALER_DISPSTAT_IRQMASK(1) | + SCALER_DISPSTAT_IRQMASK(2)); return irqret; } @@ -979,19 +990,37 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) * be unused. */ dispctrl &= ~SCALER_DISPCTRL_DSP3_MUX_MASK; - dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | - SCALER_DISPCTRL_SLVWREIRQ | - SCALER_DISPCTRL_SLVRDEIRQ | - SCALER_DISPCTRL_DSPEIEOF(0) | - SCALER_DISPCTRL_DSPEIEOF(1) | - SCALER_DISPCTRL_DSPEIEOF(2) | - SCALER_DISPCTRL_DSPEIEOLN(0) | - SCALER_DISPCTRL_DSPEIEOLN(1) | - SCALER_DISPCTRL_DSPEIEOLN(2) | - SCALER_DISPCTRL_DSPEISLUR(0) | - SCALER_DISPCTRL_DSPEISLUR(1) | - SCALER_DISPCTRL_DSPEISLUR(2) | - SCALER_DISPCTRL_SCLEIRQ); + if (!hvs->hvs5) + dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | + SCALER_DISPCTRL_SLVWREIRQ | + SCALER_DISPCTRL_SLVRDEIRQ | + SCALER_DISPCTRL_DSPEIEOF(0) | + SCALER_DISPCTRL_DSPEIEOF(1) | + SCALER_DISPCTRL_DSPEIEOF(2) | + SCALER_DISPCTRL_DSPEIEOLN(0) | + SCALER_DISPCTRL_DSPEIEOLN(1) | + SCALER_DISPCTRL_DSPEIEOLN(2) | + SCALER_DISPCTRL_DSPEISLUR(0) | + SCALER_DISPCTRL_DSPEISLUR(1) | + SCALER_DISPCTRL_DSPEISLUR(2) | + SCALER_DISPCTRL_SCLEIRQ); + else + dispctrl &= ~(SCALER5_DISPCTRL_DMAEIRQ | + SCALER5_DISPCTRL_SLVEIRQ | + SCALER5_DISPCTRL_DSPEIEOF(0) | + SCALER5_DISPCTRL_DSPEIEOF(1) | + SCALER5_DISPCTRL_DSPEIEOF(2) | + SCALER5_DISPCTRL_DSPEIEOLN(0) | + SCALER5_DISPCTRL_DSPEIEOLN(1) | + SCALER5_DISPCTRL_DSPEIEOLN(2) | + SCALER5_DISPCTRL_DSPEISLUR(0) | + SCALER5_DISPCTRL_DSPEISLUR(1) | + SCALER5_DISPCTRL_DSPEISLUR(2) | + SCALER5_DISPCTRL_DSPVSTART(0) | + SCALER5_DISPCTRL_DSPVSTART(1) | + SCALER5_DISPCTRL_DSPVSTART(2) | + SCALER_DISPCTRL_SCLEIRQ); + dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); HVS_WRITE(SCALER_DISPCTRL, dispctrl); diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index f40dd93f2cdd90..0d56a701da0a11 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -245,6 +245,23 @@ /* Enables interrupt generation on scaler profiler interrupt. */ # define SCALER_DISPCTRL_SCLEIRQ BIT(0) +/* Enables Display 0 short line and underrun contribution to + * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are + * always enabled. + */ +# define SCALER5_DISPCTRL_DSPEISLUR(x) BIT(9 + ((x) * 4)) +/* Enables Display 0 end-of-line-N contribution to + * SCALER_DISPSTAT_IRQDISP0 + */ +# define SCALER5_DISPCTRL_DSPEIEOLN(x) BIT(8 + ((x) * 4)) +/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */ +# define SCALER5_DISPCTRL_DSPEIEOF(x) BIT(7 + ((x) * 4)) +/* Enables Display 0 VSTART contribution to SCALER_DISPSTAT_IRQDISP0 */ +# define SCALER5_DISPCTRL_DSPVSTART(x) BIT(6 + ((x) * 4)) + +# define SCALER5_DISPCTRL_SLVEIRQ BIT(5) +# define SCALER5_DISPCTRL_DMAEIRQ BIT(4) + #define SCALER_DISPSTAT 0x00000004 # define SCALER_DISPSTAT_RESP_MASK VC4_MASK(15, 14) # define SCALER_DISPSTAT_RESP_SHIFT 14 @@ -253,6 +270,8 @@ # define SCALER_DISPSTAT_RESP_SLVERR 2 # define SCALER_DISPSTAT_RESP_DECERR 3 +# define SCALER5_DISPSTAT_VSTART(x) BIT(14 + ((x) * 8)) + # define SCALER_DISPSTAT_COBLOW(x) BIT(13 + ((x) * 8)) /* Set when the DISPEOLN line is done compositing. */ # define SCALER_DISPSTAT_EOLN(x) BIT(12 + ((x) * 8)) @@ -274,6 +293,8 @@ # define SCALER_DISPSTAT_IRQMASK(x) VC4_MASK(13 + ((x) * 8), \ 8 + ((x) * 8)) +# define SCALER5_DISPSTAT_IRQMASK(x) VC4_MASK(14 + ((x) * 8), \ + 8 + ((x) * 8)) /* Set on AXI invalid DMA ID error. */ # define SCALER_DISPSTAT_DMA_ERROR BIT(7) /* Set on AXI slave read decode error */ From cc0e0403e9653944ff44fd928bb85333a82280cc Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Sat, 8 Jan 2022 13:24:10 +0000 Subject: [PATCH 2/2] drm/vc4: Add alpha_blend_mode property to each plane. Move from only supporting the default of pre-multiplied alpha to supporting user specified blend mode using the standardised property. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_plane.c | 62 ++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index b323d18b511992..c6c6ef922d43c2 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -665,6 +665,48 @@ static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = { } }; +static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state) +{ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE); + + switch (state->pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED, + SCALER_POS2_ALPHA_MODE); + default: + case DRM_MODE_BLEND_PREMULTI: + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE, + SCALER_POS2_ALPHA_MODE) | + SCALER_POS2_ALPHA_PREMULT; + case DRM_MODE_BLEND_COVERAGE: + return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE, + SCALER_POS2_ALPHA_MODE); + } +} + +static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state) +{ + if (!state->fb->format->has_alpha) + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, + SCALER5_CTL2_ALPHA_MODE); + + switch (state->pixel_blend_mode) { + case DRM_MODE_BLEND_PIXEL_NONE: + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED, + SCALER5_CTL2_ALPHA_MODE); + default: + case DRM_MODE_BLEND_PREMULTI: + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE, + SCALER5_CTL2_ALPHA_MODE) | + SCALER5_CTL2_ALPHA_PREMULT; + case DRM_MODE_BLEND_COVERAGE: + return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE, + SCALER5_CTL2_ALPHA_MODE); + } +} + /* Writes out a full display list for an active plane to the plane's * private dlist state. */ @@ -926,13 +968,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane, /* Position Word 2: Source Image Size, Alpha */ vc4_state->pos2_offset = vc4_state->dlist_count; vc4_dlist_write(vc4_state, - VC4_SET_FIELD(fb->format->has_alpha ? - SCALER_POS2_ALPHA_MODE_PIPELINE : - SCALER_POS2_ALPHA_MODE_FIXED, - SCALER_POS2_ALPHA_MODE) | (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | - (fb->format->has_alpha ? - SCALER_POS2_ALPHA_PREMULT : 0) | + vc4_hvs4_get_alpha_blend_mode(state) | VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | VC4_SET_FIELD(vc4_state->src_h[0], @@ -977,14 +1014,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, VC4_SET_FIELD(state->alpha >> 4, SCALER5_CTL2_ALPHA) | - (fb->format->has_alpha ? - SCALER5_CTL2_ALPHA_PREMULT : 0) | + vc4_hvs5_get_alpha_blend_mode(state) | (mix_plane_alpha ? - SCALER5_CTL2_ALPHA_MIX : 0) | - VC4_SET_FIELD(fb->format->has_alpha ? - SCALER5_CTL2_ALPHA_MODE_PIPELINE : - SCALER5_CTL2_ALPHA_MODE_FIXED, - SCALER5_CTL2_ALPHA_MODE) + SCALER5_CTL2_ALPHA_MIX : 0) ); /* Position Word 1: Scaled Image Dimensions. */ @@ -1489,6 +1521,10 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, drm_plane_helper_add(plane, &vc4_plane_helper_funcs); drm_plane_create_alpha_property(plane); + drm_plane_create_blend_mode_property(plane, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |