From patchwork Sat May 24 01:58:34 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?St=C3=A9phane_Marchesin?= X-Patchwork-Id: 4236431 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id BBE06BF90B for ; Sat, 24 May 2014 01:58:45 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B3E1B202E6 for ; Sat, 24 May 2014 01:58:44 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id A817C202C8 for ; Sat, 24 May 2014 01:58:43 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id EDC526EF03; Fri, 23 May 2014 18:58:42 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-pb0-f53.google.com (mail-pb0-f53.google.com [209.85.160.53]) by gabe.freedesktop.org (Postfix) with ESMTP id AA3BF6EF03 for ; Fri, 23 May 2014 18:58:41 -0700 (PDT) Received: by mail-pb0-f53.google.com with SMTP id md12so4904685pbc.40 for ; Fri, 23 May 2014 18:58:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=dl06lTWANs8iV+7jIRGxVnyhNBGCJGHxBalisQNYZ/U=; b=ZzGbD63wyXMalrUhjjHuHtLphNfnykaMybnu9ZVCyaQnf+yNa5uYOjbAuSSovrgs/m 5JaqT9l/HAj8uEqRNUU+j7UzZczIY3jjrA3FCAx2mCkFo2xbNsJ/SCXMu1uOQ+YdyguX Fm8u3NNEkd7biv2RlfJorU+K+TAqWI44Q28cg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=dl06lTWANs8iV+7jIRGxVnyhNBGCJGHxBalisQNYZ/U=; b=Hcc0TsvR8QVwRiYLV4AZEZFy1oz+s7XJxgYdciL9bx7zPnjZ+lp6Z+N3juwgg3mVMP NuUjkoVFzBFb2jZuaF64qx7ZmNoVIffHrmlpzaC5hOe0HnOuVGth1aElq/S0kYf2uQG/ sbloXzOBcRN5xJJBplXtef5o/19aFygQcekDfYDVFM5iQyOPVNoC8kvPbCVipWMDlVbR 3B59MIGN1XiDYjCj1doaOl7QLhhNx7h0j4FX6c5xnWTBT6E+TdIe96OcDt8Ql1PCbdyG ets2rqBSKWo4OetkOHh9wjOWL6UfX7wbd3VywSmInopJNjV+RiXfPNgSsgRuHkVJPbQ7 Gqsg== X-Gm-Message-State: ALoCoQmRdk38CeY9FppgpTwAPFPkXWFK8PD75Xzfqj8mPfSe6zC13jgVTmySIx0c5rc54JBk/ZC6 X-Received: by 10.66.151.144 with SMTP id uq16mr10771061pab.68.1400896721521; Fri, 23 May 2014 18:58:41 -0700 (PDT) Received: from localhost ([2620:0:1000:1b01:82c1:6eff:fef8:b068]) by mx.google.com with ESMTPSA id ir10sm6699165pbc.59.2014.05.23.18.58.40 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 23 May 2014 18:58:40 -0700 (PDT) From: =?UTF-8?q?St=C3=A9phane=20Marchesin?= To: dri-devel@lists.freedesktop.org Subject: [PATCH 3/3] drm/tegra: Don't hardcode link parameters Date: Fri, 23 May 2014 18:58:34 -0700 Message-Id: <1400896714-7092-3-git-send-email-marcheu@chromium.org> X-Mailer: git-send-email 1.9.1.423.g4596e3a In-Reply-To: <1400896714-7092-1-git-send-email-marcheu@chromium.org> References: <1400896714-7092-1-git-send-email-marcheu@chromium.org> MIME-Version: 1.0 Cc: =?UTF-8?q?St=C3=A9phane=20Marchesin?= , treding@nvidia.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The currently hardcoded link parameters don't work on my eDP display, however the android driver has code to compute the parameters. This is a port of this code to the drm driver which allows the drm driver to compute the link parameters correctly. Note that we still hardcode the bpp, this will be taken care of in another patch. Signed-off-by: Stéphane Marchesin --- drivers/gpu/drm/tegra/sor.c | 199 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 190 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 23fb9b1..1fbb488 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -289,12 +289,175 @@ static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) return -ETIMEDOUT; } +struct tegra_sor_dp_link { + u32 bits_per_pixel; + + u32 activepolarity; + u32 active_count; + u32 tu_size; + u32 active_frac; + u32 watermark; +}; + +static int tegra_sor_calc_config(struct tegra_sor *sor, + struct drm_display_mode *mode, + struct tegra_sor_dp_link *tegra_link, + struct drm_dp_link *link) +{ + const u32 link_rate = link->rate * 1000; + const u64 f = 100000; /* precision factor */ + const int pclk = mode->clock * 1000; + + u32 num_linkclk_line; /* Number of link clocks per line */ + u64 ratio_f; /* Ratio of incoming to outgoing data rate */ + u64 frac_f; + u64 activesym_f; /* Activesym per TU */ + u64 activecount_f; + u32 activecount; + u32 activepolarity; + u64 approx_value_f; + u32 activefrac = 0; + u64 accumulated_error_f = 0; + u32 lowest_neg_activecount = 0; + u32 lowest_neg_activepolarity = 0; + u32 lowest_neg_tusize = 64; + u32 num_symbols_per_line; + u64 lowest_neg_activefrac = 0; + u64 lowest_neg_error_f = 64 * f; + u64 watermark_f; + + int i; + bool neg; + + if (!link_rate || !link->num_lanes || !pclk || + !tegra_link->bits_per_pixel) + return -1; + + if ((u64)pclk * tegra_link->bits_per_pixel >= + (u64)link_rate * 8 * link->num_lanes) + return -1; + + num_linkclk_line = div_u64((u64)link_rate * mode->hdisplay, pclk); + + ratio_f = (u64)pclk * tegra_link->bits_per_pixel * f; + ratio_f /= 8; + ratio_f = div_u64(ratio_f, link_rate * link->num_lanes); + + for (i = 64; i >= 32; --i) { + activesym_f = ratio_f * i; + activecount_f = div_u64(activesym_f, (u32)f) * f; + frac_f = activesym_f - activecount_f; + activecount = (u32)div_u64(activecount_f, (u32)f); + + if (frac_f < (f / 2)) /* fraction < 0.5 */ + activepolarity = 0; + else { + activepolarity = 1; + frac_f = f - frac_f; + } + + if (frac_f != 0) { + frac_f = div_u64((f * f), frac_f); /* 1/fraction */ + if (frac_f > (15 * f)) + activefrac = activepolarity ? 1 : 15; + else + activefrac = activepolarity ? + (u32)div_u64(frac_f, (u32)f) + 1 : + (u32)div_u64(frac_f, (u32)f); + } + + if (activefrac == 1) + activepolarity = 0; + + if (activepolarity == 1) + approx_value_f = activefrac ? div_u64( + activecount_f + (activefrac * f - f) * f, + (activefrac * f)) : + activecount_f + f; + else + approx_value_f = activefrac ? + activecount_f + div_u64(f, activefrac) : + activecount_f; + + if (activesym_f < approx_value_f) { + accumulated_error_f = num_linkclk_line * + div_u64(approx_value_f - activesym_f, i); + neg = true; + } else { + accumulated_error_f = num_linkclk_line * + div_u64(activesym_f - approx_value_f, i); + neg = false; + } + + if ((neg && (lowest_neg_error_f > accumulated_error_f)) || + (accumulated_error_f == 0)) { + lowest_neg_error_f = accumulated_error_f; + lowest_neg_tusize = i; + lowest_neg_activecount = activecount; + lowest_neg_activepolarity = activepolarity; + lowest_neg_activefrac = activefrac; + + if (accumulated_error_f == 0) + break; + } + } + + if (lowest_neg_activefrac == 0) { + tegra_link->activepolarity = 0; + tegra_link->active_count = lowest_neg_activepolarity ? + lowest_neg_activecount : lowest_neg_activecount - 1; + tegra_link->tu_size = lowest_neg_tusize; + tegra_link->active_frac = 1; + } else { + tegra_link->activepolarity = lowest_neg_activepolarity; + tegra_link->active_count = (u32)lowest_neg_activecount; + tegra_link->tu_size = lowest_neg_tusize; + tegra_link->active_frac = (u32)lowest_neg_activefrac; + } + + dev_dbg(sor->dev, + "dp: sor configuration: polarity: %d active count: %d " + "tu size: %d, active frac: %d\n", + tegra_link->activepolarity, + tegra_link->active_count, + tegra_link->tu_size, + tegra_link->active_frac); + + watermark_f = div_u64(ratio_f * tegra_link->tu_size * (f - ratio_f), f); + tegra_link->watermark = (u32)div_u64(watermark_f + lowest_neg_error_f, + f) + tegra_link->bits_per_pixel / 4 - 1; + num_symbols_per_line = (mode->hdisplay * tegra_link->bits_per_pixel) / + (8 * link->num_lanes); + if (tegra_link->watermark > 30) { + dev_dbg(sor->dev, + "dp: sor setting: unable to get a good tusize, " + "force watermark to 30.\n"); + tegra_link->watermark = 30; + + return -1; + } else if (tegra_link->watermark > num_symbols_per_line) { + dev_dbg(sor->dev, + "dp: sor setting: force watermark to the number " + "of symbols in the line.\n"); + tegra_link->watermark = num_symbols_per_line; + return -1; + } + + return 0; +} + + + static int tegra_output_sor_enable(struct tegra_output *output) { struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); struct drm_display_mode *mode = &dc->base.mode; unsigned int vbe, vse, hbe, hse, vbs, hbs, i; struct tegra_sor *sor = to_sor(output); + struct tegra_sor_dp_link tegra_link; + /* FIXME: properly convert to struct drm_dp_aux */ + struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux; + struct drm_dp_link link; unsigned long value; int err; @@ -311,12 +474,23 @@ static int tegra_output_sor_enable(struct tegra_output *output) err = tegra_dpaux_enable(sor->dpaux); if (err < 0) dev_err(sor->dev, "failed to enable DP: %d\n", err); + + err = drm_dp_link_probe(aux, &link); + if (err < 0) { + dev_err(sor->dev, "failed to probe eDP link: %d\n", + err); + return err; + } } err = clk_set_parent(sor->clk, sor->clk_safe); if (err < 0) dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); + tegra_link.bits_per_pixel = 24; /* XXX: don't hardcode? */ + + err = tegra_sor_calc_config(sor, mode, &tegra_link, &link); + value = tegra_sor_readl(sor, SOR_CLK_CNTRL); value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; @@ -454,7 +628,7 @@ static int tegra_output_sor_enable(struct tegra_output *output) value |= SOR_DP_LINKCTL_ENABLE; value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; - value |= SOR_DP_LINKCTL_TU_SIZE(59); /* XXX: don't hardcode? */ + value |= SOR_DP_LINKCTL_TU_SIZE(tegra_link.tu_size); value |= SOR_DP_LINKCTL_ENHANCED_FRAME; tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); @@ -470,13 +644,13 @@ static int tegra_output_sor_enable(struct tegra_output *output) value = tegra_sor_readl(sor, SOR_DP_CONFIG_0); value &= ~SOR_DP_CONFIG_WATERMARK_MASK; - value |= SOR_DP_CONFIG_WATERMARK(14); /* XXX: don't hardcode? */ + value |= SOR_DP_CONFIG_WATERMARK(tegra_link.watermark); value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; - value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(47); /* XXX: don't hardcode? */ + value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(tegra_link.active_count); value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; - value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(9); /* XXX: don't hardcode? */ + value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(tegra_link.active_frac); value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; /* XXX: don't hardcode? */ @@ -500,9 +674,6 @@ static int tegra_output_sor_enable(struct tegra_output *output) tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); if (sor->dpaux) { - /* FIXME: properly convert to struct drm_dp_aux */ - struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux; - struct drm_dp_link link; u8 rate, lanes; err = drm_dp_link_probe(aux, &link); @@ -586,12 +757,22 @@ static int tegra_output_sor_enable(struct tegra_output *output) * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete * raster, associate with display controller) */ - value = SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 | - SOR_STATE_ASY_VSYNCPOL | + value = SOR_STATE_ASY_VSYNCPOL | SOR_STATE_ASY_HSYNCPOL | SOR_STATE_ASY_PROTOCOL_DP_A | SOR_STATE_ASY_CRC_MODE_COMPLETE | SOR_STATE_ASY_OWNER(dc->pipe + 1); + switch (tegra_link.bits_per_pixel) { + default: + dev_err(sor->dev, "dp: unknown BPP value\n"); + case 24: + value |= SOR_STATE_ASY_PIXELDEPTH_BPP_24_444; + break; + case 18: + value |= SOR_STATE_ASY_PIXELDEPTH_BPP_18_444; + break; + } + tegra_sor_writel(sor, value, SOR_STATE_1); /*