In order to prevent some pixels getting stuck in an unflushable FIFO on
bcm2711, we need to enable the HVS, the pixelvalve (the CRTC) and the HDMI
controller (the encoder) in an intertwined way, and with tight delays.
However, the atomic callbacks don't really provide a way to work with
either constraints, so we need to roll our own callbacks so that we can
provide those guarantees.
Since those callbacks have been implemented and called in the CRTC code, we
can just implement them in the HDMI driver now.
Signed-off-by: Maxime Ripard <[email protected]>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 39 +++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 00592c1ada73..bbe521ab000b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -320,12 +320,17 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
vc4_hdmi_set_audio_infoframe(encoder);
}
-static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- int ret;
HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
+}
+
+static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder)
+{
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ int ret;
if (vc4_hdmi->variant->phy_disable)
vc4_hdmi->variant->phy_disable(vc4_hdmi);
@@ -341,6 +346,10 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
DRM_ERROR("Failed to release power domain: %d\n", ret);
}
+static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
{
u32 csc_ctl;
@@ -449,11 +458,10 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
"VC4_HDMI_FIFO_CTL_RECENTER_DONE");
}
-static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
+static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder)
{
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
unsigned long pixel_rate, hsm_rate;
int ret;
@@ -521,6 +529,13 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
if (vc4_hdmi->variant->set_timings)
vc4_hdmi->variant->set_timings(vc4_hdmi, mode);
+}
+
+static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder)
+{
+ struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
if (vc4_encoder->hdmi_monitor &&
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
@@ -536,6 +551,13 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
}
HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
+}
+
+static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder)
+{
+ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
+ int ret;
HDMI_WRITE(HDMI_VID_CTL,
HDMI_READ(HDMI_VID_CTL) |
@@ -582,6 +604,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
vc4_hdmi_recenter_fifo(vc4_hdmi);
}
+static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+}
+
static enum drm_mode_status
vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
const struct drm_display_mode *mode)
@@ -1362,6 +1388,11 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, vc4_hdmi);
encoder = &vc4_hdmi->encoder.base.base;
vc4_hdmi->encoder.base.type = variant->encoder_type;
+ vc4_hdmi->encoder.base.pre_crtc_configure = vc4_hdmi_encoder_pre_crtc_configure;
+ vc4_hdmi->encoder.base.pre_crtc_enable = vc4_hdmi_encoder_pre_crtc_enable;
+ vc4_hdmi->encoder.base.post_crtc_enable = vc4_hdmi_encoder_post_crtc_enable;
+ vc4_hdmi->encoder.base.post_crtc_disable = vc4_hdmi_encoder_post_crtc_disable;
+ vc4_hdmi->encoder.base.post_crtc_powerdown = vc4_hdmi_encoder_post_crtc_powerdown;
vc4_hdmi->pdev = pdev;
vc4_hdmi->variant = variant;
--
git-series 0.9.1
Hi Maxime
On Wed, 8 Jul 2020 at 18:44, Maxime Ripard <[email protected]> wrote:
>
> In order to prevent some pixels getting stuck in an unflushable FIFO on
> bcm2711, we need to enable the HVS, the pixelvalve (the CRTC) and the HDMI
> controller (the encoder) in an intertwined way, and with tight delays.
>
> However, the atomic callbacks don't really provide a way to work with
> either constraints, so we need to roll our own callbacks so that we can
> provide those guarantees.
>
> Since those callbacks have been implemented and called in the CRTC code, we
> can just implement them in the HDMI driver now.
>
> Signed-off-by: Maxime Ripard <[email protected]>
Reviewed-by: Dave Stevenson <[email protected]>
> ---
> drivers/gpu/drm/vc4/vc4_hdmi.c | 39 +++++++++++++++++++++++++++++++----
> 1 file changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> index 00592c1ada73..bbe521ab000b 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> @@ -320,12 +320,17 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
> vc4_hdmi_set_audio_infoframe(encoder);
> }
>
> -static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
> +static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder)
> {
> struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
> - int ret;
>
> HDMI_WRITE(HDMI_RAM_PACKET_CONFIG, 0);
> +}
> +
> +static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder)
> +{
> + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
> + int ret;
>
> if (vc4_hdmi->variant->phy_disable)
> vc4_hdmi->variant->phy_disable(vc4_hdmi);
> @@ -341,6 +346,10 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
> DRM_ERROR("Failed to release power domain: %d\n", ret);
> }
>
> +static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
> +{
> +}
> +
> static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable)
> {
> u32 csc_ctl;
> @@ -449,11 +458,10 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
> "VC4_HDMI_FIFO_CTL_RECENTER_DONE");
> }
>
> -static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
> +static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder)
> {
> struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
> - struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
> unsigned long pixel_rate, hsm_rate;
> int ret;
>
> @@ -521,6 +529,13 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
>
> if (vc4_hdmi->variant->set_timings)
> vc4_hdmi->variant->set_timings(vc4_hdmi, mode);
> +}
> +
> +static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder)
> +{
> + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
> + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
> + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
>
> if (vc4_encoder->hdmi_monitor &&
> drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
> @@ -536,6 +551,13 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
> }
>
> HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
> +}
> +
> +static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder)
> +{
> + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
> + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
> + int ret;
>
> HDMI_WRITE(HDMI_VID_CTL,
> HDMI_READ(HDMI_VID_CTL) |
> @@ -582,6 +604,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
> vc4_hdmi_recenter_fifo(vc4_hdmi);
> }
>
> +static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
> +{
> +}
> +
> static enum drm_mode_status
> vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder,
> const struct drm_display_mode *mode)
> @@ -1362,6 +1388,11 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
> dev_set_drvdata(dev, vc4_hdmi);
> encoder = &vc4_hdmi->encoder.base.base;
> vc4_hdmi->encoder.base.type = variant->encoder_type;
> + vc4_hdmi->encoder.base.pre_crtc_configure = vc4_hdmi_encoder_pre_crtc_configure;
> + vc4_hdmi->encoder.base.pre_crtc_enable = vc4_hdmi_encoder_pre_crtc_enable;
> + vc4_hdmi->encoder.base.post_crtc_enable = vc4_hdmi_encoder_post_crtc_enable;
> + vc4_hdmi->encoder.base.post_crtc_disable = vc4_hdmi_encoder_post_crtc_disable;
> + vc4_hdmi->encoder.base.post_crtc_powerdown = vc4_hdmi_encoder_post_crtc_powerdown;
> vc4_hdmi->pdev = pdev;
> vc4_hdmi->variant = variant;
>
> --
> git-series 0.9.1