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_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 | 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 */