On 01/20/2017 01:08 PM, Andrzej Hajda wrote:
MHL3 protocol requires registry adjustments depending on chosen video mode.
Necessary information is gathered in mode_fixup callback. In case of HDMI
video modes driver should also send special AVI and MHL infoframes.

Signed-off-by: Andrzej Hajda <a.ha...@samsung.com>
---
 drivers/gpu/drm/bridge/sil-sii8620.c | 249 +++++++++++++++++++++++++++++++----
 drivers/gpu/drm/bridge/sil-sii8620.h |  15 ++-
 2 files changed, 231 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c 
b/drivers/gpu/drm/bridge/sil-sii8620.c
index 1c76905..2c7b5b9 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -32,6 +32,8 @@

 #define SII8620_BURST_BUF_LEN 288
 #define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3)
+#define MHL1_MAX_LCLK 225000
+#define MHL3_MAX_LCLK 600000

 enum sii8620_mode {
        CM_DISCONNECTED,
@@ -62,6 +64,9 @@ struct sii8620 {
        struct regulator_bulk_data supplies[2];
        struct mutex lock; /* context lock, protects fields below */
        int error;
+       int pixel_clock;
+       unsigned int use_packed_pixel:1;
+       int video_code;
        enum sii8620_mode mode;
        enum sii8620_sink_type sink_type;
        u8 cbus_status;
@@ -69,7 +74,7 @@ struct sii8620 {
        u8 xstat[MHL_XDS_SIZE];
        u8 devcap[MHL_DCAP_SIZE];
        u8 xdevcap[MHL_XDC_SIZE];
-       u8 avif[19];
+       u8 avif[HDMI_INFOFRAME_SIZE(AVI)];
        struct edid *edid;
        unsigned int gen2_write_burst:1;
        enum sii8620_mt_state mt_state;
@@ -685,6 +690,40 @@ static void sii8620_burst_tx_rbuf_info(struct sii8620 
*ctx, int size)
        d->size = cpu_to_le16(size);
 }

+static u8 sii8620_checksum(void *ptr, int size)
+{
+       u8 *d = ptr, sum = 0;
+
+       while (size--)
+               sum += *d++;
+
+       return sum;
+}
+
+static void sii8620_mhl_burst_hdr_set(struct mhl3_burst_header *h,
+       enum mhl_burst_id id)
+{
+       h->id = cpu_to_be16(id);
+       h->total_entries = 1;
+       h->sequence_index = 1;
+}
+
+static void sii8620_burst_tx_bits_per_pixel_fmt(struct sii8620 *ctx, u8 fmt)
+{
+       struct mhl_burst_bits_per_pixel_fmt *d;
+       const int size = sizeof(*d) + sizeof(d->desc[0]);
+
+       d = sii8620_burst_get_tx_buf(ctx, size);
+       if (!d)
+               return;
+
+       sii8620_mhl_burst_hdr_set(&d->hdr, MHL_BURST_ID_BITS_PER_PIXEL_FMT);
+       d->num_entries = 1;
+       d->desc[0].stream_id = 0;
+       d->desc[0].pixel_format = fmt;
+       d->hdr.checksum -= sii8620_checksum(d, size);
+}
+
 static void sii8620_burst_rx_all(struct sii8620 *ctx)
 {
        u8 *d = ctx->burst.rx_buf;
@@ -949,32 +988,162 @@ static void sii8620_stop_video(struct sii8620 *ctx)
        sii8620_write(ctx, REG_TPI_SC, val);
 }

+static void sii8620_set_format(struct sii8620 *ctx)
+{
+       u8 out_fmt;
+
+       if (sii8620_is_mhl3(ctx)) {
+               sii8620_setbits(ctx, REG_M3_P0CTRL,
+                               BIT_M3_P0CTRL_MHL3_P0_PIXEL_MODE_PACKED,
+                               ctx->use_packed_pixel ? ~0 : 0);
+       } else {
+               if (ctx->use_packed_pixel)
+                       sii8620_write_seq_static(ctx,
+                               REG_VID_MODE, BIT_VID_MODE_M1080P,
+                               REG_MHL_TOP_CTL, BIT_MHL_TOP_CTL_MHL_PP_SEL | 1,
+                               REG_MHLTX_CTL6, 0x60
+                       );
+               else
+                       sii8620_write_seq_static(ctx,
+                               REG_VID_MODE, 0,
+                               REG_MHL_TOP_CTL, 1,
+                               REG_MHLTX_CTL6, 0xa0
+                       );
+       }
+
+       if (ctx->use_packed_pixel)
+               out_fmt = VAL_TPI_FORMAT(YCBCR422, FULL) |
+                       BIT_TPI_OUTPUT_CSCMODE709;
+       else
+               out_fmt = VAL_TPI_FORMAT(RGB, FULL);
+
+       sii8620_write_seq(ctx,
+               REG_TPI_INPUT, VAL_TPI_FORMAT(RGB, FULL),
+               REG_TPI_OUTPUT, out_fmt,
+       );
+}
+
+#define MHL3_VSIF_TYPE         0x81
+#define MHL3_VSIF_VERSION      0x03
+#define MHL3_VSIF_LENGTH       0x0f
+#define IEEE_OUI_MHL3          0x7CA61D

Should these be in mhl.h?

Some of these seem similar to the infoframe related defs
in include/linux/hdmi.h

Do you think there should be equivalent helpers for mhl infoframes
similar to hdmi_vendor_infoframe_init
and hdmi_vendor_infoframe_pack()?

Thanks,
Archit

+
+static void sii8620_mhl_infoframe_init(void *ptr, int size)
+{
+       u8 *buf = ptr;
+
+       memset(buf, 0, size);
+       buf[0] = MHL3_VSIF_TYPE;
+       buf[1] = MHL3_VSIF_VERSION;
+       buf[2] = MHL3_VSIF_LENGTH;
+       buf[4] = IEEE_OUI_MHL3 & 0xff;
+       buf[5] = (IEEE_OUI_MHL3 >> 8) & 0xff;
+       buf[6] = (IEEE_OUI_MHL3 >> 16) & 0xff;
+       buf[3] -= sii8620_checksum(buf, MHL3_VSIF_LENGTH);
+}
+
+static void sii8620_set_infoframes(struct sii8620 *ctx)
+{
+       union hdmi_infoframe frm;
+       u8 buf[31];
+       int ret;
+
+       if (!sii8620_is_mhl3(ctx) || !ctx->use_packed_pixel) {
+               sii8620_write(ctx, REG_TPI_SC,
+                       BIT_TPI_SC_TPI_OUTPUT_MODE_0_HDMI);
+               sii8620_write_buf(ctx, REG_TPI_AVI_CHSUM, ctx->avif + 3,
+                       ARRAY_SIZE(ctx->avif) - 3);
+               sii8620_write(ctx, REG_PKT_FILTER_0,
+                       BIT_PKT_FILTER_0_DROP_CEA_GAMUT_PKT |
+                       BIT_PKT_FILTER_0_DROP_MPEG_PKT |
+                       BIT_PKT_FILTER_0_DROP_GCP_PKT,
+                       BIT_PKT_FILTER_1_DROP_GEN_PKT);
+               return;
+       }
+
+       ret = hdmi_avi_infoframe_init(&frm.avi);
+       frm.avi.colorspace = HDMI_COLORSPACE_YUV422;
+       frm.avi.active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
+       frm.avi.picture_aspect = HDMI_PICTURE_ASPECT_16_9;
+       frm.avi.colorimetry = HDMI_COLORIMETRY_ITU_709;
+       frm.avi.video_code = ctx->video_code;
+       if (!ret)
+               ret = hdmi_avi_infoframe_pack(&frm.avi, buf, ARRAY_SIZE(buf));
+       if (ret > 0)
+               sii8620_write_buf(ctx, REG_TPI_AVI_CHSUM, buf + 3, ret - 3);
+       sii8620_write(ctx, REG_PKT_FILTER_0,
+               BIT_PKT_FILTER_0_DROP_CEA_GAMUT_PKT |
+               BIT_PKT_FILTER_0_DROP_MPEG_PKT |
+               BIT_PKT_FILTER_0_DROP_AVI_PKT |
+               BIT_PKT_FILTER_0_DROP_GCP_PKT,
+               BIT_PKT_FILTER_1_VSI_OVERRIDE_DIS |
+               BIT_PKT_FILTER_1_DROP_GEN_PKT |
+               BIT_PKT_FILTER_1_DROP_VSIF_PKT);
+
+       sii8620_write(ctx, REG_TPI_INFO_FSEL, BIT_TPI_INFO_FSEL_EN
+               | BIT_TPI_INFO_FSEL_RPT | VAL_TPI_INFO_FSEL_VSI);
+       sii8620_mhl_infoframe_init(buf, ARRAY_SIZE(buf));
+       sii8620_write_buf(ctx, REG_TPI_INFO_B0, buf, ARRAY_SIZE(buf));
+}
+
 static void sii8620_start_hdmi(struct sii8620 *ctx)
 {
        sii8620_write_seq_static(ctx,
                REG_RX_HDMI_CTRL2, VAL_RX_HDMI_CTRL2_DEFVAL
                        | BIT_RX_HDMI_CTRL2_USE_AV_MUTE,
                REG_VID_OVRRD, BIT_VID_OVRRD_PP_AUTO_DISABLE
-                       | BIT_VID_OVRRD_M1080P_OVRRD,
-               REG_VID_MODE, 0,
-               REG_MHL_TOP_CTL, 0x1,
-               REG_MHLTX_CTL6, 0xa0,
-               REG_TPI_INPUT, VAL_TPI_FORMAT(RGB, FULL),
-               REG_TPI_OUTPUT, VAL_TPI_FORMAT(RGB, FULL),
-       );
+                       | BIT_VID_OVRRD_M1080P_OVRRD);
+       sii8620_set_format(ctx);

-       sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
-                             MHL_DST_LM_CLK_MODE_NORMAL |
-                             MHL_DST_LM_PATH_ENABLED);
-
-       sii8620_set_auto_zone(ctx);
+       if (!sii8620_is_mhl3(ctx)) {
+               sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
+                       MHL_DST_LM_CLK_MODE_NORMAL | MHL_DST_LM_PATH_ENABLED);
+               sii8620_set_auto_zone(ctx);
+       } else {
+               static const struct {
+                       int max_clk;
+                       u8 zone;
+                       u8 link_rate;
+                       u8 rrp_decode;
+               } clk_spec[] = {
+                       { 150000, VAL_TX_ZONE_CTL3_TX_ZONE_1_5GBPS,
+                         MHL_XDS_LINK_RATE_1_5_GBPS, 0x38 },
+                       { 300000, VAL_TX_ZONE_CTL3_TX_ZONE_3GBPS,
+                         MHL_XDS_LINK_RATE_3_0_GBPS, 0x40 },
+                       { 600000, VAL_TX_ZONE_CTL3_TX_ZONE_6GBPS,
+                         MHL_XDS_LINK_RATE_6_0_GBPS, 0x40 },
+               };
+               u8 p0_ctrl = BIT_M3_P0CTRL_MHL3_P0_PORT_EN;
+               int clk = ctx->pixel_clock * (ctx->use_packed_pixel ? 2 : 3);
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(clk_spec); ++i)
+                       if (clk < clk_spec[i].max_clk)
+                               break;

-       sii8620_write(ctx, REG_TPI_SC, BIT_TPI_SC_TPI_OUTPUT_MODE_0_HDMI);
+               if (100 * clk >= 98 * clk_spec[i].max_clk)
+                       p0_ctrl |= BIT_M3_P0CTRL_MHL3_P0_UNLIMIT_EN;

-       sii8620_write_buf(ctx, REG_TPI_AVI_CHSUM, ctx->avif,
-                         ARRAY_SIZE(ctx->avif));
+               sii8620_burst_tx_bits_per_pixel_fmt(ctx, ctx->use_packed_pixel);
+               sii8620_burst_send(ctx);
+               sii8620_write_seq(ctx,
+                       REG_MHL_DP_CTL0, 0xf0,
+                       REG_MHL3_TX_ZONE_CTL, clk_spec[i].zone);
+               sii8620_setbits(ctx, REG_M3_P0CTRL,
+                       BIT_M3_P0CTRL_MHL3_P0_PORT_EN
+                       | BIT_M3_P0CTRL_MHL3_P0_UNLIMIT_EN, p0_ctrl);
+               sii8620_setbits(ctx, REG_M3_POSTM, MSK_M3_POSTM_RRP_DECODE,
+                       clk_spec[i].rrp_decode);
+               sii8620_write_seq_static(ctx,
+                       REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE
+                               | BIT_M3_CTRL_H2M_SWRST,
+                       REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE
+               );
+               sii8620_mt_write_stat(ctx, MHL_XDS_REG(AVLINK_MODE_CONTROL),
+                       clk_spec[i].link_rate);
+       }

-       sii8620_write(ctx, REG_PKT_FILTER_0, 0xa1, 0x2);
+       sii8620_set_infoframes(ctx);
 }

 static void sii8620_start_video(struct sii8620 *ctx)
@@ -1834,22 +2003,44 @@ static bool sii8620_mode_fixup(struct drm_bridge 
*bridge,
                               struct drm_display_mode *adjusted_mode)
 {
        struct sii8620 *ctx = bridge_to_sii8620(bridge);
-       bool ret = false;
-       int max_clock = 74250;
-
-       mutex_lock(&ctx->lock);
-
-       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-               goto out;
+       int max_lclk;
+       bool ret = true;

-       if (ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL)
-               max_clock = 300000;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+               return false;

-       ret = mode->clock <= max_clock;
+       mutex_lock(&ctx->lock);

-out:
+       max_lclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : MHL1_MAX_LCLK;
+       if (max_lclk > 3 * adjusted_mode->clock) {
+               ctx->use_packed_pixel = 0;
+               goto end;
+       }
+       if ((ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL) &&
+           max_lclk > 2 * adjusted_mode->clock) {
+               ctx->use_packed_pixel = 1;
+               goto end;
+       }
+       ret = false;
+end:
+       if (ret) {
+               u8 vic = drm_match_cea_mode(adjusted_mode);
+
+               if (!vic) {
+                       union hdmi_infoframe frm;
+                       u8 mhl_vic[] = { 0, 95, 94, 93, 98 };
+
+                       drm_hdmi_vendor_infoframe_from_display_mode(
+                               &frm.vendor.hdmi, adjusted_mode);
+                       vic = frm.vendor.hdmi.vic;
+                       if (vic >= ARRAY_SIZE(mhl_vic))
+                               vic = 0;
+                       vic = mhl_vic[vic];
+               }
+               ctx->video_code = vic;
+               ctx->pixel_clock = adjusted_mode->clock;
+       }
        mutex_unlock(&ctx->lock);
-
        return ret;
 }

diff --git a/drivers/gpu/drm/bridge/sil-sii8620.h 
b/drivers/gpu/drm/bridge/sil-sii8620.h
index f7bfbc3..aefae67 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.h
+++ b/drivers/gpu/drm/bridge/sil-sii8620.h
@@ -1084,10 +1084,17 @@

 /* TPI Info Frame Select, default value: 0x00 */
 #define REG_TPI_INFO_FSEL                      0x06bf
-#define BIT_TPI_INFO_FSEL_TPI_INFO_EN          BIT(7)
-#define BIT_TPI_INFO_FSEL_TPI_INFO_RPT         BIT(6)
-#define BIT_TPI_INFO_FSEL_TPI_INFO_READ_FLAG   BIT(5)
-#define MSK_TPI_INFO_FSEL_TPI_INFO_SEL         0x07
+#define BIT_TPI_INFO_FSEL_EN                   BIT(7)
+#define BIT_TPI_INFO_FSEL_RPT                  BIT(6)
+#define BIT_TPI_INFO_FSEL_READ_FLAG            BIT(5)
+#define MSK_TPI_INFO_FSEL_PKT                  0x07
+#define VAL_TPI_INFO_FSEL_AVI                  0x00
+#define VAL_TPI_INFO_FSEL_SPD                  0x01
+#define VAL_TPI_INFO_FSEL_AUD                  0x02
+#define VAL_TPI_INFO_FSEL_MPG                  0x03
+#define VAL_TPI_INFO_FSEL_GEN                  0x04
+#define VAL_TPI_INFO_FSEL_GEN2                 0x05
+#define VAL_TPI_INFO_FSEL_VSI                  0x06

 /* TPI Info Byte #0, default value: 0x00 */
 #define REG_TPI_INFO_B0                                0x06c0


--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to