aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.10/950-0417-drm-vc4-hdmi-Enable-10-12-bpc-output.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.10/950-0417-drm-vc4-hdmi-Enable-10-12-bpc-output.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.10/950-0417-drm-vc4-hdmi-Enable-10-12-bpc-output.patch203
1 files changed, 203 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.10/950-0417-drm-vc4-hdmi-Enable-10-12-bpc-output.patch b/target/linux/bcm27xx/patches-5.10/950-0417-drm-vc4-hdmi-Enable-10-12-bpc-output.patch
new file mode 100644
index 0000000000..ac821dd45a
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.10/950-0417-drm-vc4-hdmi-Enable-10-12-bpc-output.patch
@@ -0,0 +1,203 @@
+From 72a998c1462527c2d61c2f9a38525c99da442fb4 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime@cerno.tech>
+Date: Tue, 15 Dec 2020 16:42:43 +0100
+Subject: [PATCH] drm/vc4: hdmi: Enable 10/12 bpc output
+
+The BCM2711 supports higher bpc count than just 8, so let's support it in
+our driver.
+
+Signed-off-by: Maxime Ripard <maxime@cerno.tech>
+Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 70 ++++++++++++++++++++++++++++-
+ drivers/gpu/drm/vc4/vc4_hdmi.h | 1 +
+ drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 9 ++++
+ 3 files changed, 79 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -77,6 +77,17 @@
+ #define VC5_HDMI_VERTB_VSPO_SHIFT 16
+ #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)
+
++#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8
++#define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK VC4_MASK(10, 8)
++
++#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_SHIFT 0
++#define VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK VC4_MASK(3, 0)
++
++#define VC5_HDMI_GCP_CONFIG_GCP_ENABLE BIT(31)
++
++#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_SHIFT 8
++#define VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK VC4_MASK(15, 8)
++
+ # define VC4_HD_M_SW_RST BIT(2)
+ # define VC4_HD_M_ENABLE BIT(0)
+
+@@ -228,6 +239,8 @@ static void vc4_hdmi_connector_reset(str
+ if (!new_state)
+ return;
+
++ new_state->base.max_bpc = 8;
++ new_state->base.max_requested_bpc = 8;
+ drm_atomic_helper_connector_tv_reset(connector);
+ }
+
+@@ -274,12 +287,20 @@ static int vc4_hdmi_connector_init(struc
+ vc4_hdmi->ddc);
+ drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
+
++ /*
++ * Some of the properties below require access to state, like bpc.
++ * Allocate some default initial connector state with our reset helper.
++ */
++ if (connector->funcs->reset)
++ connector->funcs->reset(connector);
++
+ /* Create and attach TV margin props to this connector. */
+ ret = drm_mode_create_tv_margin_properties(dev);
+ if (ret)
+ return ret;
+
+ drm_connector_attach_tv_margin_properties(connector);
++ drm_connector_attach_max_bpc_property(connector, 8, 12);
+
+ connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT);
+@@ -554,6 +575,7 @@ static void vc5_hdmi_csc_setup(struct vc
+ }
+
+ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
++ struct drm_connector_state *state,
+ struct drm_display_mode *mode)
+ {
+ bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
+@@ -597,7 +619,9 @@ static void vc4_hdmi_set_timings(struct
+ HDMI_WRITE(HDMI_VERTB0, vertb_even);
+ HDMI_WRITE(HDMI_VERTB1, vertb);
+ }
++
+ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
++ struct drm_connector_state *state,
+ struct drm_display_mode *mode)
+ {
+ bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
+@@ -617,6 +641,9 @@ static void vc5_hdmi_set_timings(struct
+ mode->crtc_vsync_end -
+ interlaced,
+ VC4_HDMI_VERTB_VBP));
++ unsigned char gcp;
++ bool gcp_en;
++ u32 reg;
+
+ HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021);
+ HDMI_WRITE(HDMI_HORZA,
+@@ -642,6 +669,39 @@ static void vc5_hdmi_set_timings(struct
+ HDMI_WRITE(HDMI_VERTB0, vertb_even);
+ HDMI_WRITE(HDMI_VERTB1, vertb);
+
++ switch (state->max_bpc) {
++ case 12:
++ gcp = 6;
++ gcp_en = true;
++ break;
++ case 10:
++ gcp = 5;
++ gcp_en = true;
++ break;
++ case 8:
++ default:
++ gcp = 4;
++ gcp_en = false;
++ break;
++ }
++
++ reg = HDMI_READ(HDMI_DEEP_COLOR_CONFIG_1);
++ reg &= ~(VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK |
++ VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH_MASK);
++ reg |= VC4_SET_FIELD(2, VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE) |
++ VC4_SET_FIELD(gcp, VC5_HDMI_DEEP_COLOR_CONFIG_1_COLOR_DEPTH);
++ HDMI_WRITE(HDMI_DEEP_COLOR_CONFIG_1, reg);
++
++ reg = HDMI_READ(HDMI_GCP_WORD_1);
++ reg &= ~VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1_MASK;
++ reg |= VC4_SET_FIELD(gcp, VC5_HDMI_GCP_WORD_1_GCP_SUBPACKET_BYTE_1);
++ HDMI_WRITE(HDMI_GCP_WORD_1, reg);
++
++ reg = HDMI_READ(HDMI_GCP_CONFIG);
++ reg &= ~VC5_HDMI_GCP_CONFIG_GCP_ENABLE;
++ reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
++ HDMI_WRITE(HDMI_GCP_CONFIG, reg);
++
+ HDMI_WRITE(HDMI_CLOCK_STOP, 0);
+ }
+
+@@ -769,7 +829,7 @@ static void vc4_hdmi_encoder_pre_crtc_co
+ VC4_HDMI_SCHEDULER_CONTROL_IGNORE_VSYNC_PREDICTS);
+
+ if (vc4_hdmi->variant->set_timings)
+- vc4_hdmi->variant->set_timings(vc4_hdmi, mode);
++ vc4_hdmi->variant->set_timings(vc4_hdmi, conn_state, mode);
+ }
+
+ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
+@@ -890,6 +950,14 @@ static int vc4_hdmi_encoder_atomic_check
+ pixel_rate = mode->clock * 1000;
+ }
+
++ if (conn_state->max_bpc == 12) {
++ pixel_rate = pixel_rate * 150;
++ do_div(pixel_rate, 100);
++ } else if (conn_state->max_bpc == 10) {
++ pixel_rate = pixel_rate * 125;
++ do_div(pixel_rate, 100);
++ }
++
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ pixel_rate = pixel_rate * 2;
+
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
+@@ -74,6 +74,7 @@ struct vc4_hdmi_variant {
+
+ /* Callback to configure the video timings in the HDMI block */
+ void (*set_timings)(struct vc4_hdmi *vc4_hdmi,
++ struct drm_connector_state *state,
+ struct drm_display_mode *mode);
+
+ /* Callback to initialize the PHY according to the connector state */
+--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
+@@ -60,9 +60,12 @@ enum vc4_hdmi_field {
+ */
+ HDMI_CTS_0,
+ HDMI_CTS_1,
++ HDMI_DEEP_COLOR_CONFIG_1,
+ HDMI_DVP_CTL,
+ HDMI_FIFO_CTL,
+ HDMI_FRAME_COUNT,
++ HDMI_GCP_CONFIG,
++ HDMI_GCP_WORD_1,
+ HDMI_HORZA,
+ HDMI_HORZB,
+ HDMI_HOTPLUG,
+@@ -231,6 +234,9 @@ static const struct vc4_hdmi_register vc
+ VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
+ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
+ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
++ VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
++ VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
++ VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
+ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
+
+ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
+@@ -307,6 +313,9 @@ static const struct vc4_hdmi_register vc
+ VC4_HDMI_REG(HDMI_VERTB1, 0x0f8),
+ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c),
+ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0),
++ VC4_HDMI_REG(HDMI_DEEP_COLOR_CONFIG_1, 0x170),
++ VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
++ VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
+ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
+
+ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),