[PATCH 19/24] drm/bridge/sii8620: rewrite hdmi start sequence

Archit Taneja architt at codeaurora.org
Mon Jan 23 09:17:57 UTC 2017



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.hajda at 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


More information about the dri-devel mailing list