From patchwork Thu Sep 29 22:34:43 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Anholt X-Patchwork-Id: 9357237 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 31A376077A for ; Thu, 29 Sep 2016 22:35:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2258C29BB1 for ; Thu, 29 Sep 2016 22:35:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 16E8129BD1; Thu, 29 Sep 2016 22:35:13 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8E3BD29BB1 for ; Thu, 29 Sep 2016 22:35:12 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 2E1976E93C; Thu, 29 Sep 2016 22:35:11 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from anholt.net (anholt.net [50.246.234.109]) by gabe.freedesktop.org (Postfix) with ESMTP id 1C1B66E93C for ; Thu, 29 Sep 2016 22:35:07 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by anholt.net (Postfix) with ESMTP id AA00B2C9C06F; Thu, 29 Sep 2016 15:35:07 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at anholt.net Received: from anholt.net ([127.0.0.1]) by localhost (kingsolver.anholt.net [127.0.0.1]) (amavisd-new, port 10024) with LMTP id e6gXcjhO_2sa; Thu, 29 Sep 2016 15:35:04 -0700 (PDT) Received: from eliezer.anholt.net (localhost [127.0.0.1]) by anholt.net (Postfix) with ESMTP id BD6F02C9C06D; Thu, 29 Sep 2016 15:35:04 -0700 (PDT) Received: by eliezer.anholt.net (Postfix, from userid 1000) id 0E2522E830D; Thu, 29 Sep 2016 15:34:44 -0700 (PDT) From: Eric Anholt To: dri-devel@lists.freedesktop.org Subject: [PATCH 1/2] drm/vc4: Set up the AVI and SPD infoframes. Date: Thu, 29 Sep 2016 15:34:43 -0700 Message-Id: <20160929223444.29030-1-eric@anholt.net> X-Mailer: git-send-email 2.9.3 Cc: linux-kernel@vger.kernel.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP Fixes a purple bar on the left side of the screen with my Dell 2408WFP. It will also be required for supporting the double-clocked video modes. Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_hdmi.c | 136 +++++++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/vc4/vc4_regs.h | 5 ++ 2 files changed, 136 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d94108ca961d..d6b54b905bee 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -62,6 +62,8 @@ struct vc4_hdmi { struct vc4_hdmi_encoder { struct vc4_encoder base; bool hdmi_monitor; + bool limited_rgb_range; + bool rgb_range_selectable; }; static inline struct vc4_hdmi_encoder * @@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) return -ENODEV; vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid); + + if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { + vc4_encoder->rgb_range_selectable = + drm_rgb_quant_range_selectable(edid); + } + drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); @@ -272,6 +280,117 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = { .destroy = vc4_hdmi_encoder_destroy, }; +static int vc4_hdmi_stop_packet(struct drm_encoder *encoder, + enum hdmi_infoframe_type type) +{ + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + u32 packet_id = type - 0x80; + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id)); + + return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); +} + +static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, + union hdmi_infoframe *frame) +{ + struct drm_device *dev = encoder->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + u32 packet_id = frame->any.type - 0x80; + u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id; + uint8_t buffer[VC4_HDMI_PACKET_STRIDE]; + ssize_t len, i; + int ret; + + WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & + VC4_HDMI_RAM_PACKET_ENABLE), + "Packet RAM has to be on to store the packet."); + + len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer)); + if (len < 0) + return; + + ret = vc4_hdmi_stop_packet(encoder, frame->any.type); + if (ret) { + DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret); + return; + } + + for (i = 0; i < len; i += 7) { + HDMI_WRITE(packet_reg, + buffer[i + 0] << 0 | + buffer[i + 1] << 8 | + buffer[i + 2] << 16); + packet_reg += 4; + + HDMI_WRITE(packet_reg, + buffer[i + 3] << 0 | + buffer[i + 4] << 8 | + buffer[i + 5] << 16 | + buffer[i + 6] << 24); + packet_reg += 4; + } + + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id)); + ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) & + BIT(packet_id)), 100); + if (ret) + DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret); +} + +static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +{ + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct drm_crtc *crtc = encoder->crtc; + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + union hdmi_infoframe frame; + int ret; + + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode); + if (ret < 0) { + DRM_ERROR("couldn't fill AVI infoframe\n"); + return; + } + + if (vc4_encoder->rgb_range_selectable) { + if (vc4_encoder->limited_rgb_range) { + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_LIMITED; + } else { + frame.avi.quantization_range = + HDMI_QUANTIZATION_RANGE_FULL; + } + } + + vc4_hdmi_write_infoframe(encoder, &frame); +} + +static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder) +{ + union hdmi_infoframe frame; + int ret; + + ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore"); + if (ret < 0) { + DRM_ERROR("couldn't fill SPD infoframe\n"); + return; + } + + frame.spd.sdi = HDMI_SPD_SDI_PC; + + vc4_hdmi_write_infoframe(encoder, &frame); +} + +static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) +{ + vc4_hdmi_set_avi_infoframe(encoder); + vc4_hdmi_set_spd_infoframe(encoder); +} + static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *unadjusted_mode, struct drm_display_mode *mode) @@ -340,8 +459,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) { /* CEA VICs other than #1 requre limited range RGB - * output. Apply a colorspace conversion to squash - * 0-255 down to 16-235. The matrix here is: + * output unless overridden by an AVI infoframe. + * Apply a colorspace conversion to squash 0-255 down + * to 16-235. The matrix here is: * * [ 0 0 0.8594 16] * [ 0 0.8594 0 16] @@ -359,6 +479,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder, HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000); HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0); HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000); + vc4_encoder->limited_rgb_range = true; + } else { + vc4_encoder->limited_rgb_range = false; } /* The RGB order applies even when CSC is disabled. */ @@ -377,6 +500,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) struct drm_device *dev = encoder->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0); + HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16); HD_WRITE(VC4_HD_VID_CTL, HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); @@ -429,9 +554,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) | VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT); - /* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set - * up the infoframe. - */ + HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, + VC4_HDMI_RAM_PACKET_ENABLE); + + vc4_hdmi_set_infoframes(encoder); drift = HDMI_READ(VC4_HDMI_FIFO_CTL); drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK; diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index c5a423ead86f..0b868aafa8db 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -441,6 +441,8 @@ #define VC4_HDMI_RAM_PACKET_CONFIG 0x0a0 # define VC4_HDMI_RAM_PACKET_ENABLE BIT(16) +#define VC4_HDMI_RAM_PACKET_STATUS 0x0a4 + #define VC4_HDMI_HORZA 0x0c4 # define VC4_HDMI_HORZA_VPOS BIT(14) # define VC4_HDMI_HORZA_HPOS BIT(13) @@ -502,6 +504,9 @@ #define VC4_HDMI_TX_PHY_RESET_CTL 0x2c0 +#define VC4_HDMI_GCP_0 0x400 +#define VC4_HDMI_PACKET_STRIDE 0x24 + #define VC4_HD_M_CTL 0x00c # define VC4_HD_M_REGISTER_FILE_STANDBY (3 << 6) # define VC4_HD_M_RAM_STANDBY (3 << 4)