Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3762431imu; Fri, 30 Nov 2018 05:44:43 -0800 (PST) X-Google-Smtp-Source: AFSGD/WH/g4T6UWhxOQthVWxaE2hTTyg+08uCQ++Tk0vsFZV766ZCMbkezAhHe6h0Ww43JfnEBI1 X-Received: by 2002:a62:113:: with SMTP id 19mr5575687pfb.176.1543585483283; Fri, 30 Nov 2018 05:44:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1543585483; cv=none; d=google.com; s=arc-20160816; b=GhvasEaEme+U3dCwc/6Lr7jNySLHzx11qmY8U639SlsHXYCMdg4276lY7wDrstB2o8 CVj+BEFqTOPsJSeZnN3Fu1pKQZmFPww7FMefSgpOXiV/WWLU1OBlpcw5aHs/yCMFkf9D sswnUTaYdE5novSpQOOqXnx4OqkDxMZ6ef29ultdR9axC9VE1cI44gTE1520llt3xK99 Rgu3lK1ixkkjwOHwoI+WARwRgpQZ7a2/Ufz3D3zHC2wx42sMQMqkALof9XWnwN9hJYGf UEmwv+wpQOitCpaOnrY5Qrdc884EmcOVGbv/U05ZV3lLCRvTFpca574gXrMi8ehsIIP9 KqSg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=gyebw/EI077PXzjcmm/oCYFx4PvbCD+M6lZz10KG+WU=; b=Vx1EoRT88xp1ltTjszTqWPhfxXioXxIh+uqIvv5RrkrheKj509TOFhH24J+46K6jqZ 7jDN4PUjUfSxBEagGQ2RxdXDN66sSF5kxEBhC/rssYQ9ihixMpxWaWIuwM02aqSN5pm7 zFvYYpWs/PGzZMJI4IpDzNbcyPhq3wuu86yWgGxW3Rru1oioQcO9MqMdpB61hcLslhwb f+AN5FuBy+OZJ9MsrSXHOSYU/QS6EYhOs646dhQn44777L8OQE5+86zEg7nemzaKA2hR Iu6x60XwSyLCfeoWeODck70e6mx+Q5R/irWBnXpxPBA/imwgMbAo3gCS7nH7BlonUNOL xiFw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=1nf6iPuU; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e9si4935296pgm.339.2018.11.30.05.44.29; Fri, 30 Nov 2018 05:44:43 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@baylibre-com.20150623.gappssmtp.com header.s=20150623 header.b=1nf6iPuU; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727032AbeLAAwc (ORCPT + 99 others); Fri, 30 Nov 2018 19:52:32 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:36806 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726900AbeLAAwb (ORCPT ); Fri, 30 Nov 2018 19:52:31 -0500 Received: by mail-wr1-f68.google.com with SMTP id u3so5337557wrs.3 for ; Fri, 30 Nov 2018 05:43:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gyebw/EI077PXzjcmm/oCYFx4PvbCD+M6lZz10KG+WU=; b=1nf6iPuU+OMti4OPU4Mgq4GLgftxYRFhZMkbRY35GSB3l6VCAa8wEtcLy7wfR6qmtI ra4BidzI2IvcmIgfBxK49At5qgzN1L9SrheHEOmWe9zThPkP0G9+nE60zjz11aD0acIv 6XjRHG95qK+rOS43XYnGamqJebqwRintYi6igSvbPSD7AKa7wXNKpWfSVy7TvD3/p4Oa DApExTQfrAM42n8W3JdEO2oXglD/WYSLkANip7C984Ppuis4IroTBuGuy75UDa5BuWGd zBNDErS9WQUEVDklsFM8T9iklJDE2Cc96dfhZ1hGN20UO7Hn6zNRqE4/qDPQVoe+iSNX BaXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gyebw/EI077PXzjcmm/oCYFx4PvbCD+M6lZz10KG+WU=; b=CtCwMq+a6nMtA+gfD4dV02/gGBYa7CSd2Slb+DosUa435KkTQh1IzgN3vn3h2G5E31 1pie5IN3f8nRmO/kXGuS0FMZTwAE3YxggzBChaePpmKVNaf7EJhD7UWuPxHCkCzUhcve mtwRIALM4CvVqj70jnslUtA+BeAnOOu5yCE52GUI9M0IXBsPQ2RNmUNT3RAAvrM3lnFo zXpYicNpIWmeqnsJbgKJf0q3hDGX3QZc6St51IQGv2rfef0oVc7lNGfjQp6b1ZPUhCiZ VmlBBbxQ0QLyIgXiQUXD8Ux6lf8CzCT5KzvICAcaEQY70KSdRsauiBr4HktUOOXgzBTB U/Yg== X-Gm-Message-State: AA+aEWblrsIyW4SqoXrw00LAsDidenYV1GqkEAiZTBfxRv497c+pEfI9 uVwXHAIntfSdI/Lkd7j+AOZ3UMYiP4i1Yg== X-Received: by 2002:adf:ef0d:: with SMTP id e13mr4935471wro.29.1543585388974; Fri, 30 Nov 2018 05:43:08 -0800 (PST) Received: from bender.baylibre.local (lmontsouris-657-1-212-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) by smtp.gmail.com with ESMTPSA id 125sm6864898wml.35.2018.11.30.05.43.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 30 Nov 2018 05:43:08 -0800 (PST) From: Neil Armstrong To: architt@codeaurora.org, a.hajda@samsung.com, Laurent.pinchart@ideasonboard.com, Philipp Zabel , Sandy Huang , =?UTF-8?q?Heiko=20St=C3=BCbner?= , maxime.ripard@bootlin.com Cc: Neil Armstrong , dri-devel@lists.freedesktop.org, linux-amlogic@lists.infradead.org, linux-kernel@vger.kernel.org, Zheng Yang Subject: [PATCH RFC v2 4/8] drm/bridge: dw-hdmi: add support for YUV420 output Date: Fri, 30 Nov 2018 14:42:57 +0100 Message-Id: <20181130134301.17963-5-narmstrong@baylibre.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181130134301.17963-1-narmstrong@baylibre.com> References: <20181130134301.17963-1-narmstrong@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In order to support the HDMI2.0 YUV420 display modes, this patch adds support for the YUV420 TMDS Clock divided by 2 and the controller passthrough mode. YUV420 Synopsys PHY support will need some specific configuration table to support theses modes. This patch is based on work from Zheng Yang in the Rockchip Linux 4.4 BSP at [1] [1] https://github.com/rockchip-linux/kernel/tree/release-4.4 Cc: Zheng Yang Signed-off-by: Neil Armstrong --- drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 68 ++++++++++++++++++----- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index fcd941d52753..4a9a24e854db 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -99,6 +99,7 @@ struct hdmi_vmode { unsigned int mpixelclock; unsigned int mpixelrepetitioninput; unsigned int mpixelrepetitionoutput; + unsigned int mtmdsclock; }; struct hdmi_data_info { @@ -543,7 +544,7 @@ static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) { mutex_lock(&hdmi->audio_mutex); - hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock, + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock, hdmi->sample_rate); mutex_unlock(&hdmi->audio_mutex); } @@ -552,7 +553,7 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate) { mutex_lock(&hdmi->audio_mutex); hdmi->sample_rate = rate; - hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock, + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock, hdmi->sample_rate); mutex_unlock(&hdmi->audio_mutex); } @@ -653,6 +654,20 @@ static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format) } } +static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format) +{ + switch (bus_format) { + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: + return true; + + default: + return false; + } +} + static int hdmi_bus_fmt_color_depth(unsigned int bus_format) { switch (bus_format) { @@ -882,7 +897,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi) u8 val, vp_conf; if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) || - hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) { + hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) || + hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) { switch (hdmi_bus_fmt_color_depth( hdmi->hdmi_data.enc_out_bus_format)) { case 8: @@ -1036,7 +1052,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write); */ void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi) { - unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock; + unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock; /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */ if (hdmi->connector.display_info.hdmi.scdc.supported) { @@ -1198,6 +1214,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi, const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; const struct dw_hdmi_phy_config *phy_config = pdata->phy_config; + /* TOFIX Will need 420 specific PHY configuration tables */ + /* PLL/MPLL Cfg - always match on final entry */ for (; mpll_config->mpixelclock != ~0UL; mpll_config++) if (mpixelclock <= mpll_config->mpixelclock) @@ -1245,6 +1263,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) const struct dw_hdmi_phy_data *phy = hdmi->phy.data; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock; + unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock; int ret; dw_hdmi_phy_power_off(hdmi); @@ -1273,7 +1292,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi) } /* Wait for resuming transmission of TMDS clock and data */ - if (mpixelclock > HDMI14_MAX_TMDSCLK) + if (mtmdsclock > HDMI14_MAX_TMDSCLK) msleep(100); return dw_hdmi_phy_power_on(hdmi); @@ -1383,6 +1402,9 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) struct hdmi_avi_infoframe frame; u8 val; + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) + is_hdmi2_sink = true; + /* Initialise info frame from DRM mode */ drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink); @@ -1390,6 +1412,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) frame.colorspace = HDMI_COLORSPACE_YUV444; else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) frame.colorspace = HDMI_COLORSPACE_YUV422; + else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) + frame.colorspace = HDMI_COLORSPACE_YUV420; else frame.colorspace = HDMI_COLORSPACE_RGB; @@ -1547,15 +1571,18 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi; struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; - unsigned int vdisplay; + unsigned int vdisplay, hdisplay; - vmode->mpixelclock = mode->clock * 1000; + vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000; dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) + vmode->mtmdsclock /= 2; + /* Set up HDMI_FC_INVIDCONF */ inv_val = (hdmi->hdmi_data.hdcp_enable || - vmode->mpixelclock > HDMI14_MAX_TMDSCLK || + vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || hdmi_info->scdc.scrambling.low_rates ? HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE : HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE); @@ -1589,6 +1616,22 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF); + hdisplay = mode->hdisplay; + hblank = mode->htotal - mode->hdisplay; + h_de_hs = mode->hsync_start - mode->hdisplay; + hsync_len = mode->hsync_end - mode->hsync_start; + + /* + * When we're setting a YCbCr420 mode, we need + * to adjust the horizontal timing to suit. + */ + if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) { + hdisplay /= 2; + hblank /= 2; + h_de_hs /= 2; + hsync_len /= 2; + } + vdisplay = mode->vdisplay; vblank = mode->vtotal - mode->vdisplay; v_de_vs = mode->vsync_start - mode->vdisplay; @@ -1607,7 +1650,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, /* Scrambling Control */ if (hdmi_info->scdc.supported) { - if (vmode->mpixelclock > HDMI14_MAX_TMDSCLK || + if (vmode->mtmdsclock > HDMI14_MAX_TMDSCLK || hdmi_info->scdc.scrambling.low_rates) { /* * HDMI2.0 Specifies the following procedure: @@ -1645,15 +1688,14 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, } /* Set up horizontal active pixel width */ - hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1); - hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0); + hdmi_writeb(hdmi, hdisplay >> 8, HDMI_FC_INHACTV1); + hdmi_writeb(hdmi, hdisplay, HDMI_FC_INHACTV0); /* Set up vertical active lines */ hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1); hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0); /* Set up horizontal blanking pixel region width */ - hblank = mode->htotal - mode->hdisplay; hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1); hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0); @@ -1661,7 +1703,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK); /* Set up HSYNC active edge delay width (in pixel clks) */ - h_de_hs = mode->hsync_start - mode->hdisplay; hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1); hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0); @@ -1669,7 +1710,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY); /* Set up HSYNC active pulse width (in pixel clks) */ - hsync_len = mode->hsync_end - mode->hsync_start; hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1); hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0); -- 2.19.2