summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c44
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.h4
2 files changed, 43 insertions, 5 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index e58488416883..da36f529e7c2 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -351,6 +351,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
return NULL;
new_state->tmds_char_rate = vc4_state->tmds_char_rate;
+ new_state->output_bpc = vc4_state->output_bpc;
__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
return &new_state->base;
@@ -905,6 +906,8 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
struct drm_connector_state *state,
struct drm_display_mode *mode)
{
+ const struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(state);
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
@@ -952,7 +955,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
HDMI_WRITE(HDMI_VERTB0, vertb_even);
HDMI_WRITE(HDMI_VERTB1, vertb);
- switch (state->max_bpc) {
+ switch (vc4_state->output_bpc) {
case 12:
gcp = 6;
gcp_en = true;
@@ -1245,11 +1248,13 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
+ struct vc4_hdmi_connector_state *vc4_state =
+ conn_state_to_vc4_hdmi_conn_state(conn_state);
mutex_lock(&vc4_hdmi->mutex);
drm_mode_copy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode);
- vc4_hdmi->output_bpc = conn_state->max_bpc;
+ vc4_hdmi->output_bpc = vc4_state->output_bpc;
mutex_unlock(&vc4_hdmi->mutex);
}
@@ -1304,6 +1309,38 @@ vc4_hdmi_encoder_compute_clock(const struct vc4_hdmi *vc4_hdmi,
return 0;
}
+static int
+vc4_hdmi_encoder_compute_config(const struct vc4_hdmi *vc4_hdmi,
+ struct vc4_hdmi_connector_state *vc4_state,
+ const struct drm_display_mode *mode)
+{
+ struct drm_connector_state *conn_state = &vc4_state->base;
+ unsigned int max_bpc = clamp_t(unsigned int, conn_state->max_bpc, 8, 12);
+ unsigned int bpc;
+ int ret;
+
+ for (bpc = max_bpc; bpc >= 8; bpc -= 2) {
+ drm_dbg(dev, "Trying with a %d bpc output\n", bpc);
+
+ ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state,
+ mode, bpc);
+ if (ret)
+ continue;
+
+ vc4_state->output_bpc = bpc;
+
+ drm_dbg(dev,
+ "Mode %ux%u @ %uHz: Found configuration: bpc: %u, clock: %llu\n",
+ mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
+ vc4_state->output_bpc,
+ vc4_state->tmds_char_rate);
+
+ break;
+ }
+
+ return ret;
+}
+
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
#define WIFI_2_4GHz_CH1_MAX_FREQ 2422000000ULL
@@ -1337,8 +1374,7 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
tmds_char_rate = mode->clock * 1000;
}
- ret = vc4_hdmi_encoder_compute_clock(vc4_hdmi, vc4_state, mode,
- conn_state->max_bpc);
+ ret = vc4_hdmi_encoder_compute_config(vc4_hdmi, vc4_state, mode);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index cb744bc5489b..79a1a10c40a8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -218,7 +218,8 @@ struct vc4_hdmi {
bool scdc_enabled;
/**
- * @output_bpc: BPC currently being used. Protected by @mutex.
+ * @output_bpc: Copy of @vc4_connector_state.output_bpc for use
+ * outside of KMS hooks. Protected by @mutex.
*/
unsigned int output_bpc;
};
@@ -240,6 +241,7 @@ encoder_to_vc4_hdmi(struct drm_encoder *encoder)
struct vc4_hdmi_connector_state {
struct drm_connector_state base;
unsigned long long tmds_char_rate;
+ unsigned int output_bpc;
};
static inline struct vc4_hdmi_connector_state *