[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