aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrzej Hajda <a.hajda@samsung.com>2017-02-01 02:47:47 -0500
committerArchit Taneja <architt@codeaurora.org>2017-02-02 04:45:29 -0500
commitbf1722cab55a32a7a18c0155034351084bac59fa (patch)
treee29e561c1685b4f8c461b30ae83cabd0d41f90fc
parentbe1cd6fe205806fbbcf59061d7b64759b160ca31 (diff)
drm/bridge/sii8620: rewrite hdmi start sequence
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 MHL3 infoframes. The patch introduces generic helpers for handling MHL3 infoframes, in case of appearance of other users of MHL3 infoframes these function can be moved to common library. Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Archit Taneja <architt@codeaurora.org> Link: http://patchwork.freedesktop.org/patch/msgid/1485935272-17337-21-git-send-email-a.hajda@samsung.com
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.c280
-rw-r--r--drivers/gpu/drm/bridge/sil-sii8620.h15
2 files changed, 262 insertions, 33 deletions
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 80ff64322fa0..c8d06d6123c3 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -32,6 +32,8 @@
32 32
33#define SII8620_BURST_BUF_LEN 288 33#define SII8620_BURST_BUF_LEN 288
34#define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3) 34#define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3)
35#define MHL1_MAX_LCLK 225000
36#define MHL3_MAX_LCLK 600000
35 37
36enum sii8620_mode { 38enum sii8620_mode {
37 CM_DISCONNECTED, 39 CM_DISCONNECTED,
@@ -62,6 +64,9 @@ struct sii8620 {
62 struct regulator_bulk_data supplies[2]; 64 struct regulator_bulk_data supplies[2];
63 struct mutex lock; /* context lock, protects fields below */ 65 struct mutex lock; /* context lock, protects fields below */
64 int error; 66 int error;
67 int pixel_clock;
68 unsigned int use_packed_pixel:1;
69 int video_code;
65 enum sii8620_mode mode; 70 enum sii8620_mode mode;
66 enum sii8620_sink_type sink_type; 71 enum sii8620_sink_type sink_type;
67 u8 cbus_status; 72 u8 cbus_status;
@@ -69,7 +74,7 @@ struct sii8620 {
69 u8 xstat[MHL_XDS_SIZE]; 74 u8 xstat[MHL_XDS_SIZE];
70 u8 devcap[MHL_DCAP_SIZE]; 75 u8 devcap[MHL_DCAP_SIZE];
71 u8 xdevcap[MHL_XDC_SIZE]; 76 u8 xdevcap[MHL_XDC_SIZE];
72 u8 avif[19]; 77 u8 avif[HDMI_INFOFRAME_SIZE(AVI)];
73 struct edid *edid; 78 struct edid *edid;
74 unsigned int gen2_write_burst:1; 79 unsigned int gen2_write_burst:1;
75 enum sii8620_mt_state mt_state; 80 enum sii8620_mt_state mt_state;
@@ -686,6 +691,40 @@ static void sii8620_burst_tx_rbuf_info(struct sii8620 *ctx, int size)
686 d->size = cpu_to_le16(size); 691 d->size = cpu_to_le16(size);
687} 692}
688 693
694static u8 sii8620_checksum(void *ptr, int size)
695{
696 u8 *d = ptr, sum = 0;
697
698 while (size--)
699 sum += *d++;
700
701 return sum;
702}
703
704static void sii8620_mhl_burst_hdr_set(struct mhl3_burst_header *h,
705 enum mhl_burst_id id)
706{
707 h->id = cpu_to_be16(id);
708 h->total_entries = 1;
709 h->sequence_index = 1;
710}
711
712static void sii8620_burst_tx_bits_per_pixel_fmt(struct sii8620 *ctx, u8 fmt)
713{
714 struct mhl_burst_bits_per_pixel_fmt *d;
715 const int size = sizeof(*d) + sizeof(d->desc[0]);
716
717 d = sii8620_burst_get_tx_buf(ctx, size);
718 if (!d)
719 return;
720
721 sii8620_mhl_burst_hdr_set(&d->hdr, MHL_BURST_ID_BITS_PER_PIXEL_FMT);
722 d->num_entries = 1;
723 d->desc[0].stream_id = 0;
724 d->desc[0].pixel_format = fmt;
725 d->hdr.checksum -= sii8620_checksum(d, size);
726}
727
689static void sii8620_burst_rx_all(struct sii8620 *ctx) 728static void sii8620_burst_rx_all(struct sii8620 *ctx)
690{ 729{
691 u8 *d = ctx->burst.rx_buf; 730 u8 *d = ctx->burst.rx_buf;
@@ -950,32 +989,193 @@ static void sii8620_stop_video(struct sii8620 *ctx)
950 sii8620_write(ctx, REG_TPI_SC, val); 989 sii8620_write(ctx, REG_TPI_SC, val);
951} 990}
952 991
992static void sii8620_set_format(struct sii8620 *ctx)
993{
994 u8 out_fmt;
995
996 if (sii8620_is_mhl3(ctx)) {
997 sii8620_setbits(ctx, REG_M3_P0CTRL,
998 BIT_M3_P0CTRL_MHL3_P0_PIXEL_MODE_PACKED,
999 ctx->use_packed_pixel ? ~0 : 0);
1000 } else {
1001 if (ctx->use_packed_pixel)
1002 sii8620_write_seq_static(ctx,
1003 REG_VID_MODE, BIT_VID_MODE_M1080P,
1004 REG_MHL_TOP_CTL, BIT_MHL_TOP_CTL_MHL_PP_SEL | 1,
1005 REG_MHLTX_CTL6, 0x60
1006 );
1007 else
1008 sii8620_write_seq_static(ctx,
1009 REG_VID_MODE, 0,
1010 REG_MHL_TOP_CTL, 1,
1011 REG_MHLTX_CTL6, 0xa0
1012 );
1013 }
1014
1015 if (ctx->use_packed_pixel)
1016 out_fmt = VAL_TPI_FORMAT(YCBCR422, FULL) |
1017 BIT_TPI_OUTPUT_CSCMODE709;
1018 else
1019 out_fmt = VAL_TPI_FORMAT(RGB, FULL);
1020
1021 sii8620_write_seq(ctx,
1022 REG_TPI_INPUT, VAL_TPI_FORMAT(RGB, FULL),
1023 REG_TPI_OUTPUT, out_fmt,
1024 );
1025}
1026
1027static int mhl3_infoframe_init(struct mhl3_infoframe *frame)
1028{
1029 memset(frame, 0, sizeof(*frame));
1030
1031 frame->version = 3;
1032 frame->hev_format = -1;
1033 return 0;
1034}
1035
1036static ssize_t mhl3_infoframe_pack(struct mhl3_infoframe *frame,
1037 void *buffer, size_t size)
1038{
1039 const int frm_len = HDMI_INFOFRAME_HEADER_SIZE + MHL3_INFOFRAME_SIZE;
1040 u8 *ptr = buffer;
1041
1042 if (size < frm_len)
1043 return -ENOSPC;
1044
1045 memset(buffer, 0, size);
1046 ptr[0] = HDMI_INFOFRAME_TYPE_VENDOR;
1047 ptr[1] = frame->version;
1048 ptr[2] = MHL3_INFOFRAME_SIZE;
1049 ptr[4] = MHL3_IEEE_OUI & 0xff;
1050 ptr[5] = (MHL3_IEEE_OUI >> 8) & 0xff;
1051 ptr[6] = (MHL3_IEEE_OUI >> 16) & 0xff;
1052 ptr[7] = frame->video_format & 0x3;
1053 ptr[7] |= (frame->format_type & 0x7) << 2;
1054 ptr[7] |= frame->sep_audio ? BIT(5) : 0;
1055 if (frame->hev_format >= 0) {
1056 ptr[9] = 1;
1057 ptr[10] = (frame->hev_format >> 8) & 0xff;
1058 ptr[11] = frame->hev_format & 0xff;
1059 }
1060 if (frame->av_delay) {
1061 bool sign = frame->av_delay < 0;
1062 int delay = sign ? -frame->av_delay : frame->av_delay;
1063
1064 ptr[12] = (delay >> 16) & 0xf;
1065 if (sign)
1066 ptr[12] |= BIT(4);
1067 ptr[13] = (delay >> 8) & 0xff;
1068 ptr[14] = delay & 0xff;
1069 }
1070 ptr[3] -= sii8620_checksum(buffer, frm_len);
1071 return frm_len;
1072}
1073
1074static void sii8620_set_infoframes(struct sii8620 *ctx)
1075{
1076 struct mhl3_infoframe mhl_frm;
1077 union hdmi_infoframe frm;
1078 u8 buf[31];
1079 int ret;
1080
1081 if (!sii8620_is_mhl3(ctx) || !ctx->use_packed_pixel) {
1082 sii8620_write(ctx, REG_TPI_SC,
1083 BIT_TPI_SC_TPI_OUTPUT_MODE_0_HDMI);
1084 sii8620_write_buf(ctx, REG_TPI_AVI_CHSUM, ctx->avif + 3,
1085 ARRAY_SIZE(ctx->avif) - 3);
1086 sii8620_write(ctx, REG_PKT_FILTER_0,
1087 BIT_PKT_FILTER_0_DROP_CEA_GAMUT_PKT |
1088 BIT_PKT_FILTER_0_DROP_MPEG_PKT |
1089 BIT_PKT_FILTER_0_DROP_GCP_PKT,
1090 BIT_PKT_FILTER_1_DROP_GEN_PKT);
1091 return;
1092 }
1093
1094 ret = hdmi_avi_infoframe_init(&frm.avi);
1095 frm.avi.colorspace = HDMI_COLORSPACE_YUV422;
1096 frm.avi.active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
1097 frm.avi.picture_aspect = HDMI_PICTURE_ASPECT_16_9;
1098 frm.avi.colorimetry = HDMI_COLORIMETRY_ITU_709;
1099 frm.avi.video_code = ctx->video_code;
1100 if (!ret)
1101 ret = hdmi_avi_infoframe_pack(&frm.avi, buf, ARRAY_SIZE(buf));
1102 if (ret > 0)
1103 sii8620_write_buf(ctx, REG_TPI_AVI_CHSUM, buf + 3, ret - 3);
1104 sii8620_write(ctx, REG_PKT_FILTER_0,
1105 BIT_PKT_FILTER_0_DROP_CEA_GAMUT_PKT |
1106 BIT_PKT_FILTER_0_DROP_MPEG_PKT |
1107 BIT_PKT_FILTER_0_DROP_AVI_PKT |
1108 BIT_PKT_FILTER_0_DROP_GCP_PKT,
1109 BIT_PKT_FILTER_1_VSI_OVERRIDE_DIS |
1110 BIT_PKT_FILTER_1_DROP_GEN_PKT |
1111 BIT_PKT_FILTER_1_DROP_VSIF_PKT);
1112
1113 sii8620_write(ctx, REG_TPI_INFO_FSEL, BIT_TPI_INFO_FSEL_EN
1114 | BIT_TPI_INFO_FSEL_RPT | VAL_TPI_INFO_FSEL_VSI);
1115 ret = mhl3_infoframe_init(&mhl_frm);
1116 if (!ret)
1117 ret = mhl3_infoframe_pack(&mhl_frm, buf, ARRAY_SIZE(buf));
1118 sii8620_write_buf(ctx, REG_TPI_INFO_B0, buf, ret);
1119}
1120
953static void sii8620_start_hdmi(struct sii8620 *ctx) 1121static void sii8620_start_hdmi(struct sii8620 *ctx)
954{ 1122{
955 sii8620_write_seq_static(ctx, 1123 sii8620_write_seq_static(ctx,
956 REG_RX_HDMI_CTRL2, VAL_RX_HDMI_CTRL2_DEFVAL 1124 REG_RX_HDMI_CTRL2, VAL_RX_HDMI_CTRL2_DEFVAL
957 | BIT_RX_HDMI_CTRL2_USE_AV_MUTE, 1125 | BIT_RX_HDMI_CTRL2_USE_AV_MUTE,
958 REG_VID_OVRRD, BIT_VID_OVRRD_PP_AUTO_DISABLE 1126 REG_VID_OVRRD, BIT_VID_OVRRD_PP_AUTO_DISABLE
959 | BIT_VID_OVRRD_M1080P_OVRRD, 1127 | BIT_VID_OVRRD_M1080P_OVRRD);
960 REG_VID_MODE, 0, 1128 sii8620_set_format(ctx);
961 REG_MHL_TOP_CTL, 0x1,
962 REG_MHLTX_CTL6, 0xa0,
963 REG_TPI_INPUT, VAL_TPI_FORMAT(RGB, FULL),
964 REG_TPI_OUTPUT, VAL_TPI_FORMAT(RGB, FULL),
965 );
966
967 sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
968 MHL_DST_LM_CLK_MODE_NORMAL |
969 MHL_DST_LM_PATH_ENABLED);
970 1129
971 sii8620_set_auto_zone(ctx); 1130 if (!sii8620_is_mhl3(ctx)) {
1131 sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE),
1132 MHL_DST_LM_CLK_MODE_NORMAL | MHL_DST_LM_PATH_ENABLED);
1133 sii8620_set_auto_zone(ctx);
1134 } else {
1135 static const struct {
1136 int max_clk;
1137 u8 zone;
1138 u8 link_rate;
1139 u8 rrp_decode;
1140 } clk_spec[] = {
1141 { 150000, VAL_TX_ZONE_CTL3_TX_ZONE_1_5GBPS,
1142 MHL_XDS_LINK_RATE_1_5_GBPS, 0x38 },
1143 { 300000, VAL_TX_ZONE_CTL3_TX_ZONE_3GBPS,
1144 MHL_XDS_LINK_RATE_3_0_GBPS, 0x40 },
1145 { 600000, VAL_TX_ZONE_CTL3_TX_ZONE_6GBPS,
1146 MHL_XDS_LINK_RATE_6_0_GBPS, 0x40 },
1147 };
1148 u8 p0_ctrl = BIT_M3_P0CTRL_MHL3_P0_PORT_EN;
1149 int clk = ctx->pixel_clock * (ctx->use_packed_pixel ? 2 : 3);
1150 int i;
1151
1152 for (i = 0; i < ARRAY_SIZE(clk_spec); ++i)
1153 if (clk < clk_spec[i].max_clk)
1154 break;
972 1155
973 sii8620_write(ctx, REG_TPI_SC, BIT_TPI_SC_TPI_OUTPUT_MODE_0_HDMI); 1156 if (100 * clk >= 98 * clk_spec[i].max_clk)
1157 p0_ctrl |= BIT_M3_P0CTRL_MHL3_P0_UNLIMIT_EN;
974 1158
975 sii8620_write_buf(ctx, REG_TPI_AVI_CHSUM, ctx->avif, 1159 sii8620_burst_tx_bits_per_pixel_fmt(ctx, ctx->use_packed_pixel);
976 ARRAY_SIZE(ctx->avif)); 1160 sii8620_burst_send(ctx);
1161 sii8620_write_seq(ctx,
1162 REG_MHL_DP_CTL0, 0xf0,
1163 REG_MHL3_TX_ZONE_CTL, clk_spec[i].zone);
1164 sii8620_setbits(ctx, REG_M3_P0CTRL,
1165 BIT_M3_P0CTRL_MHL3_P0_PORT_EN
1166 | BIT_M3_P0CTRL_MHL3_P0_UNLIMIT_EN, p0_ctrl);
1167 sii8620_setbits(ctx, REG_M3_POSTM, MSK_M3_POSTM_RRP_DECODE,
1168 clk_spec[i].rrp_decode);
1169 sii8620_write_seq_static(ctx,
1170 REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE
1171 | BIT_M3_CTRL_H2M_SWRST,
1172 REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE
1173 );
1174 sii8620_mt_write_stat(ctx, MHL_XDS_REG(AVLINK_MODE_CONTROL),
1175 clk_spec[i].link_rate);
1176 }
977 1177
978 sii8620_write(ctx, REG_PKT_FILTER_0, 0xa1, 0x2); 1178 sii8620_set_infoframes(ctx);
979} 1179}
980 1180
981static void sii8620_start_video(struct sii8620 *ctx) 1181static void sii8620_start_video(struct sii8620 *ctx)
@@ -1835,22 +2035,44 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge,
1835 struct drm_display_mode *adjusted_mode) 2035 struct drm_display_mode *adjusted_mode)
1836{ 2036{
1837 struct sii8620 *ctx = bridge_to_sii8620(bridge); 2037 struct sii8620 *ctx = bridge_to_sii8620(bridge);
1838 bool ret = false; 2038 int max_lclk;
1839 int max_clock = 74250; 2039 bool ret = true;
1840
1841 mutex_lock(&ctx->lock);
1842
1843 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1844 goto out;
1845 2040
1846 if (ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL) 2041 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
1847 max_clock = 300000; 2042 return false;
1848 2043
1849 ret = mode->clock <= max_clock; 2044 mutex_lock(&ctx->lock);
1850 2045
1851out: 2046 max_lclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : MHL1_MAX_LCLK;
2047 if (max_lclk > 3 * adjusted_mode->clock) {
2048 ctx->use_packed_pixel = 0;
2049 goto end;
2050 }
2051 if ((ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL) &&
2052 max_lclk > 2 * adjusted_mode->clock) {
2053 ctx->use_packed_pixel = 1;
2054 goto end;
2055 }
2056 ret = false;
2057end:
2058 if (ret) {
2059 u8 vic = drm_match_cea_mode(adjusted_mode);
2060
2061 if (!vic) {
2062 union hdmi_infoframe frm;
2063 u8 mhl_vic[] = { 0, 95, 94, 93, 98 };
2064
2065 drm_hdmi_vendor_infoframe_from_display_mode(
2066 &frm.vendor.hdmi, adjusted_mode);
2067 vic = frm.vendor.hdmi.vic;
2068 if (vic >= ARRAY_SIZE(mhl_vic))
2069 vic = 0;
2070 vic = mhl_vic[vic];
2071 }
2072 ctx->video_code = vic;
2073 ctx->pixel_clock = adjusted_mode->clock;
2074 }
1852 mutex_unlock(&ctx->lock); 2075 mutex_unlock(&ctx->lock);
1853
1854 return ret; 2076 return ret;
1855} 2077}
1856 2078
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.h b/drivers/gpu/drm/bridge/sil-sii8620.h
index 683213acc756..613943aaf90d 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.h
+++ b/drivers/gpu/drm/bridge/sil-sii8620.h
@@ -1084,10 +1084,17 @@
1084 1084
1085/* TPI Info Frame Select, default value: 0x00 */ 1085/* TPI Info Frame Select, default value: 0x00 */
1086#define REG_TPI_INFO_FSEL 0x06bf 1086#define REG_TPI_INFO_FSEL 0x06bf
1087#define BIT_TPI_INFO_FSEL_TPI_INFO_EN BIT(7) 1087#define BIT_TPI_INFO_FSEL_EN BIT(7)
1088#define BIT_TPI_INFO_FSEL_TPI_INFO_RPT BIT(6) 1088#define BIT_TPI_INFO_FSEL_RPT BIT(6)
1089#define BIT_TPI_INFO_FSEL_TPI_INFO_READ_FLAG BIT(5) 1089#define BIT_TPI_INFO_FSEL_READ_FLAG BIT(5)
1090#define MSK_TPI_INFO_FSEL_TPI_INFO_SEL 0x07 1090#define MSK_TPI_INFO_FSEL_PKT 0x07
1091#define VAL_TPI_INFO_FSEL_AVI 0x00
1092#define VAL_TPI_INFO_FSEL_SPD 0x01
1093#define VAL_TPI_INFO_FSEL_AUD 0x02
1094#define VAL_TPI_INFO_FSEL_MPG 0x03
1095#define VAL_TPI_INFO_FSEL_GEN 0x04
1096#define VAL_TPI_INFO_FSEL_GEN2 0x05
1097#define VAL_TPI_INFO_FSEL_VSI 0x06
1091 1098
1092/* TPI Info Byte #0, default value: 0x00 */ 1099/* TPI Info Byte #0, default value: 0x00 */
1093#define REG_TPI_INFO_B0 0x06c0 1100#define REG_TPI_INFO_B0 0x06c0