The BCM2711 supports higher bpc count than just 8, so let's support it in
our driver.

Signed-off-by: Maxime Ripard <max...@cerno.tech>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c      | 71 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/vc4/vc4_hdmi.h      |  1 +
 drivers/gpu/drm/vc4/vc4_hdmi_regs.h |  9 ++++
 3 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index f4ff6b5db484..fb30ddd842b1 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -76,6 +76,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)
 
@@ -179,6 +190,9 @@ static void vc4_hdmi_connector_reset(struct drm_connector 
*connector)
 
        kfree(connector->state);
 
+       conn_state->base.max_bpc = 8;
+       conn_state->base.max_requested_bpc = 8;
+
        __drm_atomic_helper_connector_reset(connector, &conn_state->base);
 
        if (connector->state)
@@ -228,12 +242,20 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
                                    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);
@@ -499,6 +521,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, 
bool enable)
 }
 
 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;
@@ -542,7 +565,9 @@ static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
        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;
@@ -562,6 +587,9 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
                                        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,
@@ -587,6 +615,39 @@ 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) {
+       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);
 }
 
@@ -724,7 +785,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct 
drm_encoder *encoder,
                   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,
@@ -845,6 +906,14 @@ static int vc4_hdmi_encoder_atomic_check(struct 
drm_encoder *encoder,
                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;
 
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 60c53d7c9bad..4c8994cfd932 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -77,6 +77,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 */
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h 
b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
index 7c6b4818f245..013fd57febd8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
@@ -59,9 +59,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,
@@ -229,6 +232,9 @@ static const struct vc4_hdmi_register 
vc5_hdmi_hdmi0_fields[] = {
        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),
@@ -305,6 +311,9 @@ static const struct vc4_hdmi_register 
vc5_hdmi_hdmi1_fields[] = {
        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),
-- 
2.28.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to