drm/bridge: ti-sn65dsi86: Use 18-bit DP if we can
authorDouglas Anderson <dianders@chromium.org>
Wed, 18 Dec 2019 22:35:27 +0000 (14:35 -0800)
committerNeil Armstrong <narmstrong@baylibre.com>
Thu, 13 Feb 2020 09:21:45 +0000 (10:21 +0100)
The current bridge driver always forced us to use 24 bits per pixel
over the DP link.  This is a waste if you are hooked up to a panel
that only supports 6 bits per color or fewer, since in that case you
can run at 18 bits per pixel and thus end up at a lower DP clock rate.

Let's support this.

While at it, let's clean up the math in the function to avoid rounding
errors (and round in the correct direction when we have to round).
Numbers are sufficiently small (because mode->clock is in kHz) that we
don't need to worry about integer overflow.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
[narmstrong: s/ran/can/]
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191218143416.v3.6.Iaf8d698f4e5253d658ae283d2fd07268076a7c27@changeid
drivers/gpu/drm/bridge/ti-sn65dsi86.c

index 5c1c6ed387e0e41ecfe36a869ec515a0f8fdfc19..ea57778b93d0de1a842dc2d683ac335d236940d7 100644 (file)
@@ -51,6 +51,7 @@
 #define SN_ENH_FRAME_REG                       0x5A
 #define  VSTREAM_ENABLE                                BIT(3)
 #define SN_DATA_FORMAT_REG                     0x5B
+#define  BPP_18_RGB                            BIT(0)
 #define SN_HPD_DISABLE_REG                     0x5C
 #define  HPD_DISABLE                           BIT(0)
 #define SN_AUX_WDATA_REG(x)                    (0x64 + (x))
@@ -436,6 +437,14 @@ static void ti_sn_bridge_set_dsi_rate(struct ti_sn_bridge *pdata)
        regmap_write(pdata->regmap, SN_DSIA_CLK_FREQ_REG, val);
 }
 
+static unsigned int ti_sn_bridge_get_bpp(struct ti_sn_bridge *pdata)
+{
+       if (pdata->connector.display_info.bpc <= 6)
+               return 18;
+       else
+               return 24;
+}
+
 /**
  * LUT index corresponds to register value and
  * LUT values corresponds to dp data rate supported
@@ -447,21 +456,17 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
 
 static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
 {
-       unsigned int bit_rate_mhz, dp_rate_mhz;
+       unsigned int bit_rate_khz, dp_rate_mhz;
        unsigned int i;
        struct drm_display_mode *mode =
                &pdata->bridge.encoder->crtc->state->adjusted_mode;
 
-       /*
-        * Calculate minimum bit rate based on our pixel clock.  At
-        * the moment this driver never sets the DP_18BPP_EN bit in
-        * register 0x5b so we hardcode 24bpp.
-        */
-       bit_rate_mhz = (mode->clock / 1000) * 24;
+       /* Calculate minimum bit rate based on our pixel clock. */
+       bit_rate_khz = mode->clock * ti_sn_bridge_get_bpp(pdata);
 
        /* Calculate minimum DP data rate, taking 80% as per DP spec */
-       dp_rate_mhz = ((bit_rate_mhz / pdata->dp_lanes) * DP_CLK_FUDGE_NUM) /
-                                                       DP_CLK_FUDGE_DEN;
+       dp_rate_mhz = DIV_ROUND_UP(bit_rate_khz * DP_CLK_FUDGE_NUM,
+                                  1000 * pdata->dp_lanes * DP_CLK_FUDGE_DEN);
 
        for (i = 1; i < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1; i++)
                if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
@@ -550,6 +555,10 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
        regmap_update_bits(pdata->regmap, SN_DSI_LANES_REG,
                           CHA_DSI_LANES_MASK, val);
 
+       /* Set the DP output format (18 bpp or 24 bpp) */
+       val = (ti_sn_bridge_get_bpp(pdata) == 18) ? BPP_18_RGB : 0;
+       regmap_update_bits(pdata->regmap, SN_DATA_FORMAT_REG, BPP_18_RGB, val);
+
        /* DP lane config */
        val = DP_NUM_LANES(min(pdata->dp_lanes, 3));
        regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,