drm/vc4: Enable limited range RGB output on HDMI with CEA modes.
authorEric Anholt <eric@anholt.net>
Fri, 16 Sep 2016 09:59:45 +0000 (10:59 +0100)
committerEric Anholt <eric@anholt.net>
Thu, 6 Oct 2016 18:58:26 +0000 (11:58 -0700)
Fixes broken grayscale ramps on many HDMI monitors, where large areas
at the ends of the ramp would all appear as black or white.

Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_regs.h

index 68ad10634b29ec7b716f70f0b5fd9f2046da1fe5..29be7b7273df5b2c75d3162d72097efe62ec93df 100644 (file)
@@ -298,6 +298,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
                                      struct drm_display_mode *unadjusted_mode,
                                      struct drm_display_mode *mode)
 {
+       struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
        struct drm_device *dev = encoder->dev;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        bool debug_dump_regs = false;
@@ -313,6 +314,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
        u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
                     VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
                                   VC4_HDMI_VERTB_VBP));
+       u32 csc_ctl;
 
        if (debug_dump_regs) {
                DRM_INFO("HDMI regs before:\n");
@@ -351,9 +353,34 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
                 (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
                 (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
 
+       csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
+                               VC4_HD_CSC_CTL_ORDER);
+
+       if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
+               /* CEA VICs other than #1 requre limited range RGB
+                * output.  Apply a colorspace conversion to squash
+                * 0-255 down to 16-235.  The matrix here is:
+                *
+                * [ 0      0      0.8594 16]
+                * [ 0      0.8594 0      16]
+                * [ 0.8594 0      0      16]
+                * [ 0      0      0       1]
+                */
+               csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
+               csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
+               csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
+                                        VC4_HD_CSC_CTL_MODE);
+
+               HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
+               HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
+               HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
+               HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
+       }
+
        /* The RGB order applies even when CSC is disabled. */
-       HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
-                                              VC4_HD_CSC_CTL_ORDER));
+       HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
 
        HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
 
index 160942a9180e716e6c6d890214f0fc6e0e081ecd..9ecd6ff3d493ffca5249256ce99dc2de2b21e0ee 100644 (file)
 # define VC4_HD_CSC_CTL_MODE_SHIFT             2
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB   0
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB   1
-# define VC4_HD_CSC_CTL_MODE_CUSTOM            2
+# define VC4_HD_CSC_CTL_MODE_CUSTOM            3
 # define VC4_HD_CSC_CTL_RGB2YCC                        BIT(1)
 # define VC4_HD_CSC_CTL_ENABLE                 BIT(0)
 
+#define VC4_HD_CSC_12_11                       0x044
+#define VC4_HD_CSC_14_13                       0x048
+#define VC4_HD_CSC_22_21                       0x04c
+#define VC4_HD_CSC_24_23                       0x050
+#define VC4_HD_CSC_32_31                       0x054
+#define VC4_HD_CSC_34_33                       0x058
+
 #define VC4_HD_FRAME_COUNT                     0x068
 
 /* HVS display list information. */